MS365.VBA.officeAddin

officeaddin:: excel context input

손잡기 2025. 6. 26. 07:56

 Excel JavaScript API 1.7 이상에서 지원

 

 

기본코드

// React 컴포넌트에서 사용할 경우
import { useEffect, useState } from 'react';

export function ExcelTaskPaneComponent() {
  const [selectedCellValue, setSelectedCellValue] = useState<string>('');
  const [selectedCellAddress, setSelectedCellAddress] = useState<string>('');

  useEffect(() => {
    // Office API 초기화 확인
    if (typeof Office !== 'undefined') {
      Office.onReady(() => {
        setupSelectionChangeHandler();
      });
    }
  }, []);

  const setupSelectionChangeHandler = async () => {
    try {
      await Excel.run(async (context) => {
        // 활성 워크시트 가져오기
        const worksheet = context.workbook.worksheets.getActiveWorksheet();
        
        // 선택 변경 이벤트 핸들러 등록
        worksheet.onSelectionChanged.add(handleSelectionChange);
        
        await context.sync();
        console.log('Selection change event handler registered');
      });
    } catch (error) {
      console.error('Failed to setup selection change handler:', error);
    }
  };

  const handleSelectionChange = async (event: Excel.WorksheetSelectionChangedEventArgs) => {
    try {
      await Excel.run(async (context) => {
        // 선택된 범위 가져오기
        const selectedRange = context.workbook.getSelectedRange();
        
        // 선택된 범위의 주소와 값 로드
        selectedRange.load(['address', 'values']);
        
        await context.sync();
        
        // 첫 번째 셀의 값 가져오기 (단일 셀인 경우)
        const cellValue = selectedRange.values[0][0]?.toString() || '';
        
        // 상태 업데이트
        setSelectedCellAddress(selectedRange.address);
        setSelectedCellValue(cellValue);
      });
    } catch (error) {
      console.error('Error handling selection change:', error);
    }
  };

  return (
    <div style={{ padding: '20px' }}>
      <h3>Selected Cell Information</h3>
      
      <div style={{ marginBottom: '10px' }}>
        <label>Cell Address:</label>
        <input 
          type="text" 
          value={selectedCellAddress} 
          readOnly 
          style={{ marginLeft: '10px', width: '200px' }}
        />
      </div>
      
      <div style={{ marginBottom: '10px' }}>
        <label>Cell Value:</label>
        <input 
          type="text" 
          value={selectedCellValue} 
          onChange={(e) => setSelectedCellValue(e.target.value)}
          style={{ marginLeft: '10px', width: '200px' }}
        />
      </div>
      
      <button onClick={updateCellValue}>
        Update Cell Value
      </button>
    </div>
  );

  // 선택된 셀 값 업데이트 함수
  async function updateCellValue() {
    try {
      await Excel.run(async (context) => {
        const selectedRange = context.workbook.getSelectedRange();
        selectedRange.values = [[selectedCellValue]];
        
        await context.sync();
        console.log('Cell value updated');
      });
    } catch (error) {
      console.error('Error updating cell value:', error);
    }
  }
}

 

 

 

 

다중셀지원

export function AdvancedExcelTaskPane() {
  const [cellData, setCellData] = useState<{
    address: string;
    values: any[][];
    isMultiCell: boolean;
  }>({
    address: '',
    values: [],
    isMultiCell: false
  });

  useEffect(() => {
    if (typeof Office !== 'undefined') {
      Office.onReady(() => {
        setupAdvancedSelectionHandler();
      });
    }
  }, []);

  const setupAdvancedSelectionHandler = async () => {
    try {
      await Excel.run(async (context) => {
        // 모든 워크시트에서 선택 변경 감지
        const worksheets = context.workbook.worksheets;
        worksheets.onSelectionChanged.add(handleAdvancedSelectionChange);
        
        await context.sync();
        console.log('Advanced selection change handler registered');
      });
    } catch (error) {
      console.error('Failed to setup advanced selection handler:', error);
    }
  };

  const handleAdvancedSelectionChange = async (event: Excel.WorksheetSelectionChangedEventArgs) => {
    try {
      await Excel.run(async (context) => {
        const selectedRange = context.workbook.getSelectedRange();
        selectedRange.load(['address', 'values', 'rowCount', 'columnCount']);
        
        await context.sync();
        
        const isMultiCell = selectedRange.rowCount > 1 || selectedRange.columnCount > 1;
        
        setCellData({
          address: selectedRange.address,
          values: selectedRange.values,
          isMultiCell: isMultiCell
        });
      });
    } catch (error) {
      console.error('Error in advanced selection handler:', error);
    }
  };

  return (
    <div style={{ padding: '20px' }}>
      <h3>Cell Selection Details</h3>
      
      <div style={{ marginBottom: '10px' }}>
        <strong>Selected Range:</strong> {cellData.address}
      </div>
      
      {cellData.isMultiCell ? (
        <div>
          <strong>Multiple cells selected:</strong>
          <table border={1} style={{ marginTop: '10px' }}>
            <tbody>
              {cellData.values.map((row, rowIndex) => (
                <tr key={rowIndex}>
                  {row.map((cell, colIndex) => (
                    <td key={colIndex} style={{ padding: '5px' }}>
                      <input 
                        type="text" 
                        value={cell?.toString() || ''} 
                        onChange={(e) => updateCellInRange(rowIndex, colIndex, e.target.value)}
                        style={{ width: '80px' }}
                      />
                    </td>
                  ))}
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      ) : (
        <div>
          <label>Single Cell Value:</label>
          <input 
            type="text" 
            value={cellData.values[0]?.[0]?.toString() || ''} 
            onChange={(e) => updateSingleCell(e.target.value)}
            style={{ marginLeft: '10px', width: '200px' }}
          />
        </div>
      )}
    </div>
  );

  function updateCellInRange(row: number, col: number, value: string) {
    const newValues = [...cellData.values];
    if (!newValues[row]) newValues[row] = [];
    newValues[row][col] = value;
    
    setCellData(prev => ({
      ...prev,
      values: newValues
    }));
  }

  function updateSingleCell(value: string) {
    setCellData(prev => ({
      ...prev,
      values: [[value]]
    }));
  }
}

 

 

이벤트정리(메모리 누수방지)

 

useEffect(() => {
  let eventHandler: Excel.EventHandlerResult<Excel.WorksheetSelectionChangedEventArgs>;

  const setupHandler = async () => {
    await Excel.run(async (context) => {
      const worksheet = context.workbook.worksheets.getActiveWorksheet();
      eventHandler = worksheet.onSelectionChanged.add(handleSelectionChange);
      await context.sync();
    });
  };

  if (typeof Office !== 'undefined') {
    Office.onReady(setupHandler);
  }

  // 컴포넌트 언마운트 시 이벤트 핸들러 제거
  return () => {
    if (eventHandler) {
      Excel.run(async (context) => {
        eventHandler.remove();
        await context.sync();
      });
    }
  };
}, []);

 

_

반응형