# Unity 如何獲取Texture 的記憶體大小 在Unity中,要獲取Texture的記憶體文件大小,可以使用UnityEditor.TextureUtil類中的一些函數。這些函數提供了獲取存儲記憶體大小和運行時記憶體大小的方法。由於UnityEditor.TextureUtil是一個內部類,我們需要 ...
背景
應用開發過程中,常常會對用戶輸入內容進行驗證,通常是基於類型、範圍、格式或者特定的要求進行驗證,以確保輸入符合預期。例如郵箱輸入框校驗輸入內容是否符合郵箱格式。在WPF中,數據模型允許將ValidationRules
與Binding
對象關聯,可以通過繼承ValidationRule
類並重寫Validate
方法來創建自定義規則。
問題
儘管創建自定義校驗規則可以滿足大部分應用場景,但是當我們校驗規則是動態變化的時候就有些麻煩了。例如,開發一個文件管理系統,要求文件名不能與系統中已有的文件重名。這個時候需要先獲取到系統中已有文件的名稱列表,並綁定到ValidationRule
上。然而ValidationRule
不是繼承於DepedencyObject
,不能添加依賴屬性,自定義的驗證規則中的參數不支持綁定。
解決方案
接下來將給出一個解決方案,讓ValidationRule支持參數綁定。思路如下:
首先自定義一個繼承DepedencyObject的類ValidationParams,併在其中添加依賴屬性用於綁定數據。
public class ValidationParams:DependencyObject
{
public object Data
{
get { return (object)GetValue(DataProperty); }
set { SetValue(DataProperty, value); }
}
public static readonly DependencyProperty DataProperty =
DependencyProperty.Register("Data", typeof(object), typeof(ValidationParams), new PropertyMetadata(null));
}
然後在自定義校驗規則FileNameValidationRule中添加ValidationParams類型的屬性。
public class FileNameValidationRule : ValidationRule
{
public ValidationParams Params { get; set; }
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
Regex reg = new Regex("[^()()a-zA-Z0-9_\u4e00-\u9fa5]");
if (reg.IsMatch(value.ToString()) || value.ToString().Trim() == "")
return new ValidationResult(false, "請輸入字母、數字、下劃線或漢字");
else if ((Params.Data as List<string>).Contains(value.ToString()))
return new ValidationResult(false, "名稱重覆,請修改名稱");
else
return new ValidationResult(true, null);
}
}
最後在XAML中輸入框數據綁定時添加校驗規則,並把已有文件的名稱列表綁定到校驗規則參數中。
<ctoolkit:WatermarkTextBox x:Name="FileNameWTextBox" Watermark="請輸入文件名稱" ShowClearButton="True" Width="418" Height="30" HorizontalAlignment="Left" Margin="90,0,0,0">
<TextBox.Text>
<Binding Path="FileName" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<chelper:FileNameValidationRule>
<chelper:FileNameValidationRule.Params>
<chelper:ValidationParams Data="{Binding DataContext.ListFileName,ElementName=self}"/>
</chelper:FileNameValidationRule.Params>
</chelper:FileNameValidationRule>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</ctoolkit:WatermarkTextBox>
然而,事情並沒有那麼順利,ValidationParams的Data始終是空的,也就是綁定不成功。這是為什麼呢?經過研究發現,FileNameValidationRule並不在可視化樹上,無法繼承和訪問到DataContext,因此綁定失敗。
解決這個問題的方法其實也不太複雜(其實找解決辦法也是花了點時間)。思路是利用資源字典和Freezable類。
- 即使不在邏輯樹中的對象也可以通過key訪問到資源。
- Freezable類的主要目的是定義具有可修改狀態和只讀狀態的對象,但是比較幸運的是這個類的實例不在可視化樹或邏輯樹中也可以繼承到DataContext,目前我也不清楚這裡的原理。
根據這兩點信息,首先定義一個繼承於Freezable的類BindingProxy,包含一個用於綁定數據的依賴屬性DataProperty。
public class BindingProxy : Freezable
{
protected override Freezable CreateInstanceCore()
{
return new BindingProxy();
}
public object Data
{
get { return (object)GetValue(DataProperty); }
set { SetValue(DataProperty, value); }
}
// Using a DependencyProperty as the backing store for Data. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DataProperty =
DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new PropertyMetadata(null));
}
然後在WatermarkTextBox的資源字典中實例化BindingProxy,並綁定已有文件名稱列表,然後在校驗規則參數ValidationParams的Data中綁定BindingProxy實例。
<ctoolkit:WatermarkTextBox x:Name="FileNameWTextBox" Watermark="請輸入文件名稱" ShowClearButton="True" Width="418" Height="30" HorizontalAlignment="Left" Margin="90,0,0,0">
<ctoolkit:WatermarkTextBox.Resources>
<chelper:BindingProxy x:Key="FileNamesProxy" Data="{Binding DataContext.ListFileName,ElementName=self}"/>
</ctoolkit:WatermarkTextBox.Resources>
//上文中已有代碼此處省略...
<chelper:ValidationParams Data="{Binding Source={StaticResource FileNamesProxy},Path=Data}"/>
//上文中已有代碼此處省略...
</ctoolkit:WatermarkTextBox>
小結
在WPF中,預設情況下,DataContext是通過可視化樹來傳遞的。父元素的DataContext會自動傳遞給其子元素,以便子元素可以訪問父元素的數據對象。但是,不在可視化樹上的對象,無法繼承和直接綁定到DataContext。本文的案例也是在這個地方卡殼了,雖然最終解決了這個問題,但是Freezable類如何繼承到DataContext的原理還有待研究。