728x90
반응형
728x170
▶ Data.cs
using System.Xml.Linq;
namespace ResourceMerger
{
/// <summary>
/// 데이터
/// </summary>
public class Data
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Property
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 문서 - Document
/// <summary>
/// 문서
/// </summary>
public XDocument Document { get; set; }
#endregion
#region 종속 카운트 - DependencyCount
/// <summary>
/// 종속 카운트
/// </summary>
public int DependencyCount { get; set; }
#endregion
//////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
////////////////////////////////////////////////////////////////////////////////////////// Public
#region 생성자 - Data(document, dependencyCount)
/// <summary>
/// 생성자
/// </summary>
/// <param name="document">문서</param>
/// <param name="dependencyCount">종속 카운트</param>
public Data(XDocument document, int dependencyCount)
{
Document = document;
DependencyCount = dependencyCount;
}
#endregion
}
}
728x90
▶ ResourceHelper.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
namespace ResourceMerger
{
/// <summary>
/// 리소스 헬퍼
/// </summary>
public static class ResourceHelper
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Public
#region 리소스 딕셔너리 병합하기 - MergeResourceDictionary(projectDirectoryPath, projectName, sourceRelativeFilePath, targetRelativeFilePath, errorMessage)
/// <summary>
/// 리소스 딕셔너리 병합하기
/// </summary>
/// <param name="projectDirectoryPath">프로젝트 디렉토리 경로</param>
/// <param name="projectName">프로젝트명</param>
/// <param name="sourceRelativeFilePath">소스 파일 상대 경로</param>
/// <param name="targetRelativeFilePath">타겟 파일 상대 경로</param>
/// <param name="errorMessage">에러 메시지</param>
/// <returns>처리 결과</returns>
public static bool MergeResourceDictionary
(
string projectDirectoryPath,
string projectName,
string sourceRelativeFilePath,
string targetRelativeFilePath,
out string errorMessage
)
{
if(!Directory.Exists(projectDirectoryPath))
{
errorMessage = $"PROJECT DIRECTORY PATH DOES NOT EXISTS : {projectDirectoryPath}";
return false;
}
projectName = string.IsNullOrWhiteSpace(projectName) ? Path.GetFileName(Path.GetDirectoryName(projectDirectoryPath)) : projectName;
if(!sourceRelativeFilePath.EndsWith(".xaml", StringComparison.InvariantCultureIgnoreCase))
{
errorMessage = $"RELATIVE SOURCE FILE EXTENSON IS NOT .XAML : {sourceRelativeFilePath}";
return false;
}
if(!targetRelativeFilePath.EndsWith(".xaml", StringComparison.InvariantCultureIgnoreCase))
{
errorMessage = $"RELATIVE TARGET FILE EXTENSON IS NOT .XAML : {targetRelativeFilePath}";
return false;
}
string sourceFilePath = Path.Combine(projectDirectoryPath, sourceRelativeFilePath);
if(!File.Exists(sourceFilePath))
{
errorMessage = $"SOURCE FILE DOES NOT EXISTS : {sourceFilePath}";
return false;
}
XDocument sourceDocument = XDocument.Load(sourceFilePath);
XNamespace defaultNamespace = sourceDocument.Root.GetDefaultNamespace();
string resourceDictionaryName = sourceDocument.Root.Name.LocalName;
XDocument targetDocument = XDocument.Parse("<" + resourceDictionaryName + " xmlns=\"" + defaultNamespace + "\"/>");
Dictionary<string, Data> dataDictionary = new Dictionary<string, Data>();
try
{
PrepareDataDictionary(ref dataDictionary, projectDirectoryPath, projectName, sourceRelativeFilePath);
}
catch(Exception exception)
{
errorMessage = $"ERROR PREPARE DATA DICTIONARY\n{exception.ToString()}";
return false;
}
foreach(KeyValuePair<string, Data> keyValuePair in dataDictionary.OrderByDescending(item => item.Value.DependencyCount))
{
foreach(XAttribute attribute in keyValuePair.Value.Document.Root.Attributes())
{
targetDocument.Root.SetAttributeValue(attribute.Name, attribute.Value);
}
targetDocument.Root.Add
(
keyValuePair.Value.Document.Root.Elements().Where(e => !e.Name.LocalName.StartsWith(resourceDictionaryName))
);
}
using(MemoryStream stream = new MemoryStream())
{
targetDocument.Save(stream);
if(CompareByteArray(Path.Combine(projectDirectoryPath, targetRelativeFilePath), stream.ToArray()))
{
errorMessage = null;
return true;
}
}
string targetFilePath = Path.Combine(projectDirectoryPath, targetRelativeFilePath);
targetDocument.Save(targetFilePath);
errorMessage = null;
return true;
}
#endregion
//////////////////////////////////////////////////////////////////////////////// Private
#region 데이터 딕셔너리 준비하기 - PrepareDataDictionary(dataDictionary, projectDirectoryPath, projectName, sourceRelativeFilePath, first, parentDependencyCount)
/// <summary>
/// 데이터 딕셔너리 준비하기
/// </summary>
/// <param name="dataDictionary">데이터 딕셔너리</param>
/// <param name="projectDirectoryPath">프로젝트 디렉토리 경로</param>
/// <param name="projectName">프로젝트명</param>
/// <param name="sourceRelativeFilePath">소스 상대 파일 경로</param>
/// <param name="first">첫번째 여부</param>
/// <param name="parentDependencyCount">부모 종속 카운트</param>
private static void PrepareDataDictionary
(
ref Dictionary<string, Data> dataDictionary,
string projectDirectoryPath,
string projectName,
string sourceRelativeFilePath,
bool first = true,
int parentDependencyCount = 0
)
{
string sourceFilePath = Path.Combine(projectDirectoryPath, sourceRelativeFilePath.TrimStart('/'));
if(!File.Exists(sourceFilePath))
{
throw new Exception($"SOURCE FILE PATH DOES NOT EXISTS : {sourceFilePath}");
}
XDocument document = XDocument.Load(sourceFilePath);
string resourceDictionaryName = document.Root.Name.LocalName;
XNamespace defaultNamespace = document.Root.GetDefaultNamespace();
if(dataDictionary.ContainsKey(sourceFilePath))
{
dataDictionary[sourceFilePath].DependencyCount = Math.Max
(
dataDictionary[sourceFilePath].DependencyCount + 1,
parentDependencyCount + 1
);
}
else
{
dataDictionary.Add
(
sourceFilePath,
new Data(document, first ? -1 : parentDependencyCount + 1)
);
}
foreach(XElement dictionaryElement in document.Root.Descendants(defaultNamespace + resourceDictionaryName))
{
PrepareDataDictionary
(
ref dataDictionary,
projectDirectoryPath,
projectName,
dictionaryElement.Attribute("Source").Value.Replace("/" + projectName + ";component/", string.Empty),
false,
dataDictionary[sourceFilePath].DependencyCount
);
}
}
#endregion
#region 바이트 배열 비교하기 - CompareByteArray(targetFilePath, newByteArray)
/// <summary>
/// 바이트 배열 비교하기
/// </summary>
/// <param name="targetFilePath">타겟 파일 경로</param>
/// <param name="newByteArray">신규 바이트 배열</param>
/// <returns>바이트 배열 비교 결과</returns>
private static bool CompareByteArray(string targetFilePath, byte[] newByteArray)
{
string finalTargetFilePath = targetFilePath.Replace("/", "\\");
if(!File.Exists(finalTargetFilePath))
{
return false;
}
byte[] targetFileByteArray = File.ReadAllBytes(finalTargetFilePath);
return newByteArray.SequenceEqual(targetFileByteArray); ;
}
#endregion
}
}
300x250
▶ Program.cs
using System;
namespace ResourceMerger
{
/// <summary>
/// 프로그램
/// </summary>
public class Program
{
//////////////////////////////////////////////////////////////////////////////////////////////////// Method
////////////////////////////////////////////////////////////////////////////////////////// Static
//////////////////////////////////////////////////////////////////////////////// Private
#region 프로그램 시작하기 - Main(argumentArray)
/// <summary>
/// 프로그램 시작하기
/// </summary>
/// <param name="argumentArray">인자 배열</param>
private static void Main(string[] argumentArray)
{
int argumentArrayLength = argumentArray.Length;
if(argumentArrayLength != 4)
{
Console.WriteLine($"INVALID ARGUMENT ARRAY LENGTH : {argumentArray.Length}");
return;
}
string projectDirectoryPath = argumentArray[0];
string projectName = argumentArray[1];
string relativeSourceFilePath = argumentArray[2];
string relativeTargetFilePath = argumentArray[3];
string errorMessage;
bool result = ResourceHelper.MergeResourceDictionary
(
projectDirectoryPath,
projectName,
relativeSourceFilePath,
relativeTargetFilePath,
out errorMessage
);
if(!result)
{
Console.WriteLine(errorMessage);
}
}
#endregion
}
}
728x90
반응형
그리드형(광고전용)
'C# > WPF' 카테고리의 다른 글
[C#/WPF] Canvas 클래스 : 자식 엘리먼트 드래그하기 (0) | 2021.02.13 |
---|---|
[C#/WPF] ListBox 클래스 : 확장 가능한 리스트 박스 사용하기 (0) | 2021.02.12 |
[C#/WPF] 누겟 설치 : System.Windows.Interactivity.WPF (0) | 2021.02.12 |
[C#/WPF] 디자인 타임에서 리소스 딕셔너리 로드하기 (0) | 2021.02.12 |
[C#/WPF] 리소스 병합 설정하기 (0) | 2021.02.12 |
[C#/WPF] 애니메이션 메시지 컨트롤 사용하기 (0) | 2021.02.11 |
[C#/WPF] 3D 애니메이션 시계 사용하기 (0) | 2021.02.11 |
[C#/WPF] SVG 파일을 XAML로 변환하기 (0) | 2021.02.10 |
[C#/WPF] 이미지 물방울 애니메이션(Drip Animation) 사용하기 (0) | 2021.02.09 |
[C#/WPF] 이미지 롤 애니메이션(Roll Animation) 사용하기 (0) | 2021.02.08 |
댓글을 달아 주세요