binding
RaisePropertyChanged
屬性改變事件
https://blog.csdn.net/cselmu9/article/details/8275255
?
?
INotification?通知
https://www.cnblogs.com/lonelyxmas/p/10669406.html
?
binding
<TextBox Name="textBox1" Text="{Binding Path=Value,ElementName=slider1}"/> <Slider HorizontalAlignment="Left" Margin="84,106,0,0" Name="slider1" VerticalAlignment="Top" />有的時候我們會在代碼中我們看大Path是一個“.”或者干脆沒有Path的Binding,著實讓人摸不著頭腦。原來這是一種比較特殊的情況---Binding源本身就是一種數據且不需要Path來指明。典型的string,int等基本類型都是這樣,他們是實例本身就是數據,我們無法指定通過那個屬性來訪問這個數據,這是我們只需要將這個數據設置為.就可以了。在XAML中這個.可以忽略不寫,但是在C#中編程必須要帶上。
在使用集合類型的數據作為列表控件的ItemSource時一般會考慮使用ObservableCollection<T>替換List<T>,因為ObservableCollection<T>類實現了INotifyChange和INotifyPropertyChanged接口,能把集合的變化立刻通知顯示到它的列表控件上,改變會立刻顯示出來。
?
?
單值轉換實例,IValueConverter
?
1.當值從綁定源傳播給綁定目標時,調用方法Convert
2.當值從綁定目標傳播給綁定源時,調用此方法ConvertBack,方法ConvertBack的實現必須是方法Convert的反向實現。
/// <summary>/// 自定義事件轉換/// </summary>public class TimeConver : IValueConverter{//當值從綁定源傳播給綁定目標時,調用方法Convertpublic object Convert(object value, Type targetType, object parameter, CultureInfo culture){if (value == null)return DependencyProperty.UnsetValue;DateTime date = (DateTime)value;return date.ToString("yyyy-MM-dd");}//當值從綁定目標傳播給綁定源時,調用此方法ConvertBackpublic object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture){string str = value as string;DateTime txtDate;if (DateTime.TryParse(str, out txtDate)){return txtDate;}return DependencyProperty.UnsetValue;}}注:返回值DependencyProperty.UnsetValue表示轉換器沒有生成任何值。
在xaml中引用TimeConver的命名空間
xmlns:local="clr-namespace:AudioDemo.View"在xaml中定義Resources
<Window.Resources><local:TimeConver x:Key="cvtDate"/> </Window.Resources>在xaml重指定Binding值使用自定義Converter轉換
<Grid><DatePicker x:Name="dateOne" HorizontalAlignment="Left" Margin="85,50,0,0" VerticalAlignment="Top" Width="183"SelectedDateFormat="Long"/><TextBox x:Name="textBox" Text="{Binding ElementName=dateOne,Path=SelectedDate,Converter={StaticResource cvtDate}}" HorizontalAlignment="Left" Height="23" Margin="85,105,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="183"/><Label x:Name="label" Content="選擇結果:" HorizontalAlignment="Left" Margin="19,105,0,0" VerticalAlignment="Top"/><Label x:Name="label1" Content="{Binding ElementName=dateOne,Path=Text}" HorizontalAlignment="Left" Margin="85,145,0,0" VerticalAlignment="Top"/> </Grid> <TextBox x:Name="textBox" Text="{Binding ElementName=dateOne,Path=SelectedDate,Converter={StaticResource cvtDate}}" HorizontalAlignment="Left" Height="23" Margin="85,105,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="183"/> public class ColorConverter : IMultiValueConverter {//正向修改public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture){if (values == null || values.Length < 2)return DependencyProperty.UnsetValue;double verValue = (double)values[0];double horValue = (double)values[1];if (verValue > horValue)return new SolidColorBrush(Colors.Green);else if (verValue < horValue)return new SolidColorBrush(Colors.Red);return new SolidColorBrush(Colors.Yellow);}//反向修改public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture){//返回空,標記不可雙向轉換return null;} }?
xmlns:local="clr-namespace:AudioDemo.View" <Window.Resources><local:ColorConverter x:Key="cvtColor"/> </Window.Resources> <Grid><Label x:Name="label" Content="縱向值:" HorizontalAlignment="Left" Margin="10,40,0,0" VerticalAlignment="Top"/><Label x:Name="label1" Content="橫向值:" HorizontalAlignment="Left" Margin="10,80,0,0" VerticalAlignment="Top"/><Slider x:Name="sliderVer" HorizontalAlignment="Left" Margin="75,43,0,0" VerticalAlignment="Top" Width="192"/><Slider x:Name="sliderHor" HorizontalAlignment="Left" Margin="75,81,0,0" VerticalAlignment="Top" Width="192"/><Ellipse HorizontalAlignment="Left" Height="100" Margin="75,120,0,0" Stroke="Black" VerticalAlignment="Top" Width="100"><Ellipse.Fill><MultiBinding Converter="{StaticResource cvtColor}"><Binding Path="Value" ElementName="sliderVer"/><Binding Path="Value" ElementName="sliderHor"/></MultiBinding></Ellipse.Fill></Ellipse> </Grid> public class RGBConverter : IMultiValueConverter {//正向修改,整合顏色值public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture){if (values == null || values.Length < 3)return null;byte r = System.Convert.ToByte(values[0]);byte g = System.Convert.ToByte(values[1]);byte b = System.Convert.ToByte(values[2]);Color col = Color.FromRgb(r, g, b);SolidColorBrush brush = new SolidColorBrush(col);return brush;}public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture){return null;} } xmlns:local="clr-namespace:AudioDemo.View" <Window.Resources><local:RGBConverter x:Key="rgbCvt"/> </Window.Resources> <Grid><Label x:Name="label" Content="Red:" HorizontalAlignment="Left" Margin="10,48,0,0" VerticalAlignment="Top"/><Label x:Name="label_Copy" Content="Green:" HorizontalAlignment="Left" Margin="7,85,0,0" VerticalAlignment="Top"/><Label x:Name="label_Copy1" Content="Blue:" HorizontalAlignment="Left" Margin="7,123,0,0" VerticalAlignment="Top"/><Slider x:Name="slider_r" Minimum="0" Maximum="255" Ticks="1" HorizontalAlignment="Left" Margin="68,53,0,0" VerticalAlignment="Top" Width="207"/><Slider x:Name="slider_g" Minimum="0" Maximum="255" Ticks="1" HorizontalAlignment="Left" Margin="68,91,0,0" VerticalAlignment="Top" Width="207"/><Slider x:Name="slider_b" Minimum="0" Maximum="255" Ticks="1" HorizontalAlignment="Left" Margin="68,124,0,0" VerticalAlignment="Top" Width="207"/><Rectangle HorizontalAlignment="Left" Height="90" Margin="68,160,0,0" Stroke="Black" VerticalAlignment="Top" Width="142"><Rectangle.Fill><MultiBinding Converter="{StaticResource rgbCvt}"><Binding ElementName="slider_r" Path="Value"></Binding><Binding ElementName="slider_g" Path="Value"></Binding><Binding ElementName="slider_b" Path="Value"></Binding></MultiBinding></Rectangle.Fill></Rectangle></Grid> <Button Content="Test"><Button.Background><MultiBinding Converter="{StaticResource mutiBoolConverter}"><Binding Path="IsEnableCredentialsAdded"/><Binding Path="IsOld"/></MultiBinding></Button.Background> </Button>?
<TextBox Height="20" Margin="0,0,10,87" Text="{Binding ElementName=slider1,Path=Value}" BorderThickness="1"/><Slider Maximum="100" Margin="0,50,0,35" Name="slider1"/>?
改善優化WPF Binding
下面的內容在修正錯誤的同時,還將對原有的Binding做一些小小的改進。
?
情況如下:在將數據庫中的DataTable對象的DefaultView通過XAML語言Binding到listView1對象的ItemsSource上時總是失敗。
?
答案那就是使用DataContext,這里先來梳理一下Binding的一些基本概念及使用方法。
?
?
l?典型的Binding具有四個重要組成部分:Binding目標對象(binding target object)、目標對象屬性(target property)、Binding數據源(binding source)、Path(用于指明要從數據源中取得的值,就是我們通常寫的屬性名稱)。
?
?
例如:想要把一個員工(Employee)的姓名(EmpName)Binding顯示到一個TextBox的Text屬性上。
?
分析一下其中的4個組成部分:Binding目標對象是TextBox(因為它要最終使用這些數據);目標對象屬性是TextProperty(這里要注意,不是Text屬性,而是與Text屬性相對應的Dependency Property,通常命名是屬性名+Property);
?
數據源是員工(Employee);Path是EmpName。我的經驗是:剛開始使用Binding的時候由于還不熟悉,建議在做之前先在心理把這4個部分對號入座一下,等日后就可以熟悉成自然了。
?
l?目標對象屬性一定要是Dependency Property。由于只有DependencyObject類及其子類能夠定義Dependency Property,因此,Binding目標對象就必須是DependencyObject類及其子類了。另一方面反過來說,UIElement(DependencyObject的子類)的大多數屬性都有與其對應的Dependency Property,因此,大多數的UIElement屬性我們都可以利用其Dependency Property作為目標對象屬性從而與數據源建立Binding。
?
l?再有一點,建立Binding的數據源不一定要是一個CLR對象,也可以是XML數據、ADO.NET對象及DependencyObject。
?
關于為什么binding的對象一定要是DependencyObject,為什么binding對象的屬性一定要是dependency property,這個我就不知道了。
在我第一次看到在XAML中設置Binding的語法時,簡直是滿頭霧水。這東西到底怎么回事,簡直就沒有章法可循,一會兒ElementName,一會兒Source,還有時什么都沒有,就一個{Binding },再有就是Mode,UpdateSourceTrigger等,簡直沒有頭緒。
?
不過只要打開MSDN,看一下System.Windows.Data.Binding對象,似乎開始有點感覺了,查看Binding對象的屬性欄(Properties),你會發現,原來我們在XAML中設置Binding時使用的東西和Binding對象的屬性好像都是一一對應的。
?
確實如此,在XAML中設置Binding就是在這只System.Windows.Data.Binding對象,這里先提醒一下大家。
?
WPF可不是就這么一個Binding噢,實時上,從BindingBase繼承過來的有三個兄弟,Binding只是最常用而已。
找到了binding的老家,相信大家對{Binding ElementName=ElemName, Path=PropertyName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, …}這樣的語法應該清楚了吧。
那么{Binding }?及{Binding XXXX}這樣的語法呢?其實可以就是等于new Binding()及new Binding(XXXX),其實可以考慮成是分別使用了Binding的兩種構造方法,而XXXX的作用自然也就清晰了。
其實和{Binding Path=XXXX}是等價的,都是設置Path屬性的。至于這里的Path屬性在我們平常使用時其實是用來設置屬性名的地方,為什么不直接叫做是PropertyName之類的名字呢?這個又要留著以后思考了。
當一個數據源與一個UIElement形成Binding后,數據源的改變,如果傳遞給UIElement的指定屬性?
同樣,當UIElement中指定屬性值改變了,如何才能夠通知到數據源?要討論這個問題,需要按數據源來分類進行討論。這個分類并不是互斥的之前存在一些交集。
因此,同一種Binding場景可能適用于多種情況。
下面的內容是來自MSDN中《Binding Sources Overview》中的內容,由于怕翻譯的不好而誤導大家,所以分類的名稱還是使用英文吧。
Using a CLR Class as the Binding Source Object
在典型的Binding情景中,一個CLR?對象作為數據源,將其中一個屬性值Binding到某個UIElement的屬性上(以上面顯示員工姓名的情景為例。
?
用XAML實現<TextBox Text=”{Binding Source=Employee, Path=EmpName}” />)。當數據源屬性值變化了,相應讓UIElement中對應屬性變化。
?
需要實現一個中通知機制,最簡單的方法是通過實現INotifyPropertyChanged接口完成此操作。具體實現,可以參考MSDN上的文章《How to: Implement Property Change Notification》。
?
其實就是實現了”public?event?PropertyChangedEventHandler PropertyChanged;”事件,通常的做法是在上面加封裝一個”protected void OnPropertyChanged(string name)”函數。在屬性的set方法結尾處,調用此函數實現通知的作用。
?
如果不實行此接口,則必須自己實現一套通知系統。為你的類中的每一個想要實現通知機制的屬性創建一個PropertyChanged模板。
?
即為你的每一個屬性創建一個名為”PropertyNameChanged”事件,其中PropertyName是與這個事件對應的屬性名稱。然后在屬性發生變化是觸發這個事件。(聽起來就麻煩,我也懶得去實踐驗證了)
?
如果以上兩種方法都無法實現的話,那么就只好在你認為需要的時候顯示的調用UpdateTarget方法來手動更新了。
?
(這種方法沒用過,感覺已經失去了Binding的意義了)
Entire Objects Used as a Binding Source
可以理解為將整個對象作為數據源,與上一個題目的區別很小。
?
基本上可以認為是原來Binding實現的是數據源屬性與UIElement屬性之間的Binding,而這次是直接將一個Object對象與一個UIElement的屬性進行Binding了。
?
這種情況可以使用Binding的Source屬性指明數據源(假設Employee對象與一個ListBox實現banding,用XAML實現<ListBox ItemsSource=”{Binding Employee}” />),或者還可以將DataContext屬性設置為Employee(DataContext屬性只有UIElement的一個子類System.Windows.FrameworkElement及其子類才會有)。
?
這樣,在設置ItemsSource時就可以直接使用”{Binding }”這樣的語法了。當然,DataContext屬性設置成Employee還是需要使用DataContext=”{Binding Employee}”語句的。
?
有人在這里會嘲笑這一舉動實在是啰嗦,事實上,DataContext屬性是非常有用的。之所以Binding對象失敗而最終不得不使用C#語句進行Binding就是因為沒有設置DataContext。
?
因為,當我們使用{Binding Source= Employee, Path=”EmpName”}設置屬性后,WPF查找Source對象是根據Element Tree逐級向上自己的Parent Element查找的,查找每一Element上的DataContext所指定的內容是否包含這一Source內容,并以第一個匹配到的結果作為最終對象。
?
也就是說,DataContext是按照Element Tree向下繼承的,并且決定這WPF在運行時能否找到我們所制定的Source對象。即使我們使用{Binding Path=”EmpName”}的語句也是如此。
?
比較常見的做法是,當我們有大量的Element需要與一個數據源中的眾多屬性實現Binding時,我們可以直接在一個公共Parent Element的DataContext上設置這一對象(甚至可以是整個window或page上),這將會極大的加少我們重復的代碼量,同時也會是程序更加可讀。
當我們需要使用的數據源是一個集合時,如果想要實現改變通知的機制。
?
同樣需要實現一個接口INotifyCollectionChanged用來在集合發生改變時發起,用法單個對象是實現INotifyPropertyChanged接口類似。
?
首先是將上以前做的不是很好的那一段代碼改成XAML語言實現。
?
將TextBox標簽中的Text屬性與上面listView1中被選定的記錄(listView1.SelectedItem)中對應屬性(例如:ContactID)做Binding。
?
實現后如圖所示:
<TextBox?Text="{Binding?ElementName=listView1,?Path=SelectedItem.ContactID}"?MinWidth="100" />
?
看以來代碼有點長,而且,下面的幾個TextBox也都存在大量的重復內容,這里就可以考慮使用上面所說的DataContext了。
將listView1中被選定的記錄(listView1.SelectedItem)作為DataContext放在公共Parent Element上,做法如下:
?
<WrapPanel?Grid.Row="1"?Orientation="Horizontal"?DataContext="{Binding?ElementName=listView1,?Path=SelectedItem}">
然后剩下的代碼就可以簡化很多了:
<StackPanel?Orientation="Horizontal"?Margin="5,2,5,2">
<TextBlock?Text="ContactID:"?TextAlignment="Center" />
<TextBox?Text="{Binding?ContactID}"?MinWidth="100" />
</StackPanel>
<StackPanel?Orientation="Horizontal"?Margin="5,2,5,2">
<TextBlock?Text="FirstName:"?TextAlignment="Center" />
<TextBox?Text="{Binding?FirstName}"?MinWidth="100" />
</StackPanel>
<StackPanel?Orientation="Horizontal"?Margin="5,2,5,2">
<TextBlock?Text="LastName:"?TextAlignment="Center" />
<TextBox?Text="{Binding?EmailAddress}"?MinWidth="100" />
</StackPanel>
<StackPanel?Orientation="Horizontal"?Margin="5,2,5,2">
<TextBlock?Text="EmailAddress:"?TextAlignment="Center" />
<TextBox?Text="{Binding?LastName}"?MinWidth="100" />
</StackPanel>
?
原來的SelectionChanged事件處理方法現在已經沒有用了,將多余的代碼去掉:
?
<ListView?Name="listView1"?SelectionChanged="listView1_SelectionChanged"?MinWidth="280"?>
?
后臺代碼中的對應方法也可以刪掉了private?void?listView1_SelectionChanged(object?sender,?SelectionChangedEventArgs?e)。
?
F5 Debug運行一下,結果和原來是完全一樣的。
在上一文中無得以選擇使用C#實現Binding的部分代碼,現在使用XAML語言實現,有幾種方案可以選擇,通過如下幾步實現:
1)?將原先建立給listView1建立Binding那一大串代碼刪掉,替換成如下代碼:
listView1.DataContext = dt.DefaultView;
執行結果如下圖所示:
?
?
2)?將其與listView1的ItemsSource屬性建立Binding,設置每一列的header及DisplayMemberBinding值。
這里由于DataContext的原因,ItemsSource可以寫成"{Binding?}"的形式而其Children Element也都可以簡寫成"{Binding?ContactID}"這樣的形式。
<ListView?Name="listView1"?MinWidth="280"?ItemsSource="{Binding?}">
<ListView.View>
<GridView?x:Name="gridView1">
<GridView.Columns>
<GridViewColumn?DisplayMemberBinding="{Binding?ContactID}"?Header="ContactID"></GridViewColumn>
<GridViewColumn?DisplayMemberBinding="{Binding?FirstName}"?Header="FirstName"></GridViewColumn>
<GridViewColumn?DisplayMemberBinding="{Binding?LastName}"?Header="LastName"></GridViewColumn>
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
改造完后,運行結果會發現,效果和原來是一樣。效率提高了,代碼更加簡化。
UpdateSourceTrigger??綁定的UpdateSourceTrigger屬性用來控制改變的值何時傳遞給源。
PropertyChanged??一旦綁定的屬性值改變,源會立即更新
LostFocus?一旦目標控件失去焦點,源就會被更新
Explicit?源不會更新除非你手動來操作
要使用事件綁定需要借助System.Windows. interactivity,如果安裝了Blend,里面就包含了這個dll。需要在Interaction.Triggers里面添加一個或多個EventTrigger并指定關注的的事件名稱,在EventTrigger中通過InvokeCommandAction來綁定事件對應的命令。圖中所示綁定了主窗口的Loaded事件,在事件觸發后會調用綁定的命令對象LoadedCommand的Execute方法執行命令,當命令綁定需要參數時可以通過綁定CommandParameter實現。需要指出的是之前在實現MyCommand的Execute方法時我們加入了CanExecute的判斷,因此事件觸發后是否能夠真正執行綁定的命令也受到綁定的LoadedCommand的CanExecute方法的影響。
?
https://www.cnblogs.com/durow/p/4860836.html
注意;
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"就是導入Blend的dll,然后在控件內部用<i:Interaction.Triggers/>即可,其它應該一看就知道,我通過事件觸發器,來引發ViewModel中兩個Command,第二個Command的參數是Button對象,通過ElementName=btn來指定。
<Button Name="btn" Content="Button" Height="33"? VerticalAlignment="Top" Width="109">
?? ??? ?<i:Interaction.Triggers>
?? ??? ??? ??<i:EventTrigger EventName="Click">
?? ??? ??? ??? ? ?<i:InvokeCommandAction Command="{Binding Command1}" CommandParameter="10" />
? ? ? ? ? ? ?</i:EventTrigger>
? ? ? ? ? ? <i:EventTrigger EventName="MouseMove">
? ? ? ? ? ? ? <i:InvokeCommandAction Command="{Binding Command2}" CommandParameter="{Binding ElementName=btn}" />
? ? ? ? ? ? </i:EventTrigger>
? ? ? ?</i:Interaction.Triggers>
?</Button>
---------------------?
進行Bingding時,如果明確知道數據源的Name,就能用Source或者ElementName進行綁定,但是有時候我們需要綁定的數據源可能沒有明確的Name,此時我們就需要利用Bingding的RelativeSource進行綁定。
一、控件關聯自身的屬性
?<TextBox Name="textbox" FontSize="24" Margin="10"
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?Text="{Binding RelativeSource={RelativeSource Mode=Self},Path=Name}"/>
二、控件關聯其父級容器的屬性
<TextBox Name="textbox" Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Grid},AncestorLevel=1},Path=Name}"/>
RelativeSource屬性的數據類型為RelativeSource類,AncestorLevel指的是以Bingding目標控件為起點的層級偏移量,d2的偏移量是1,g2的偏移量是2,AncestorType指的是要找的目標對象的類型。值得注意的是AncestorLevel需要參考AncestorType使用,如上面設置了AncestorType={x:Type Grid},則Bingding在尋找時會忽略非Grid的控件,此時g2的偏移量是1,g1的偏移量是2,DockPanel被忽略。
將一個Behavior拖到一個元素上,就能使這個元素具有某種行為,而實現這種行為的程序集和你的項目是獨立的,你創建的Behavior也可以被其他人使用。
public class MouseDoubleClickCopyTextBehavior : Behavior<FrameworkElement>
? ? {
? ? ? ? /// <summary>
? ? ? ? /// 需要復制的內容
? ? ? ? /// </summary>
? ? ? ? public string CopyText
? ? ? ? {
? ? ? ? ? ? get { return (string)GetValue(CopyTextProperty); }
? ? ? ? ? ? set { SetValue(CopyTextProperty, value); }
? ? ? ? }
? ? ? ? public static readonly DependencyProperty CopyTextProperty = DependencyProperty.Register("CopyText", typeof(string), typeof(MouseDoubleClickCopyTextBehavior), new PropertyMetadata(null));
? ? ? ? protected override void OnAttached()
? ? ? ? {
? ? ? ? ? ? base.OnAttached();
? ? ? ? ? ? AssociatedObject.PreviewMouseLeftButtonDown += AssociatedObject_PreviewMouseLeftButtonDown;
? ? ? ? }
? ? ? ? protected override void OnDetaching()
? ? ? ? {
? ? ? ? ? ? base.OnDetaching();
? ? ? ? ? ? AssociatedObject.PreviewMouseLeftButtonDown -= AssociatedObject_PreviewMouseLeftButtonDown;
? ? ? ? }
? ? ? ? void AssociatedObject_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
? ? ? ? {
? ? ? ? ? ? if (e.ClickCount >= 2)
? ? ? ? ? ? ? ? Clipboard.SetDataObject(CopyText);
? ? ? ? }
獲取構成在合并字典的各種資源字典 ResourceDictionary 字典的集合??合并多個外部資源字典成為本地字典
合并多個外部資源字典成為本地字典。當需要合并更多字典的時候只要在ResourceDictionary.MergedDictionaries節中順序增加引用。
合并字典(MergedDictionaries 集合中的字典)中對同一對象的同一子元素進行定義的時候,會產生覆蓋效果:在這種情況下,所返回的資源將來自在 MergedDictionaries 集合中最后一個找到的字典。(在這里會顯示myresourcedictionary2.xaml中的定義)。
合并字典(MergedDictionaries 集合中的字典)中對同一對象的不同子元素定義的時候會產生疊加效果。
?<UserControl.Resources>
? ? ? ? <ResourceDictionary>
? ? ? ? ? ? <ResourceDictionary.MergedDictionaries>
? ? ? ? ? ? ? ? <ResourceDictionary Source="xxx.xaml"></ResourceDictionary>
? ? ? ? ? ? </ResourceDictionary.MergedDictionaries>
? ? ? ? </ResourceDictionary>
? ? </UserControl.Resources>
總結
- 上一篇: 亿阳信通笔试题
- 下一篇: 5G的落地现状与未来变局