前言:
Wpf開發過程中,最經常使用的功能之一,就是使用者控件(UserControl)了。使用者控件可以用于開發使用者自己的控件進行使用,甚至可以用于打造一套屬于自己的UI架構。依賴屬性(DependencyProperty)是為使用者控件提供可支援雙向綁定的必備技巧之一,同樣用處也非常廣泛。
以下案例,為了圖友善,我以之前的部落格的基礎為模闆,直接進行開發。如有遇到疑問的地方,可以檢視先前的部落格(WPF使用prism架構+Unity IOC容器實作MVVM雙向綁定和依賴注入)的文章做個前瞻了解:
https://www.cnblogs.com/weskynet/p/15967764.html
以下是正文(代碼在文末)
0、配置環境
用戶端環境:WIN 10 專業版
VS開發環境:VS 2022 企業版
運作時環境:.NET 6
開發語言:C#
前端架構:WPF
1、建立了一個使用者控件,裡面畫了一個實心圓,以及一個文本控件的組合,當作我要實驗使用的使用者控件(TestUserControl)。
2、在主窗體裡面進行引用,可以看到引用以後,會在工具箱上顯示新增的使用者控件
3、為了測試友善,我直接在先前的Lo'gin頁面直接進行添加該使用者控件,效果如下。
4、運作效果如下。由于該使用者控件沒有設定過任何屬性,是以現在是沒有任何事件、也沒有辦法更改預設文本等資訊的。
5、接下來進行設定屬性,用于可以直接更改TextName屬性的Text值。設定一個MyText屬性,用于可以擷取和設定使用者控件内的TextBlock的Text值。
6、然後可以在Xaml裡面直接通過更改MyText的屬性,來更新顯示的Text值。如下圖所示,設定MyText屬性後,設定值為666,同步更新成666了。
7、但是如果想要實作雙向綁定,其實還不太夠,直接Binding會提示錯誤XDG0062:Object of type 'System.Windows.Data.Binding' cannot be converted to type 'System.String'. 如圖。
8、以上問題可以通過自定義依賴屬性來解決。在使用者控件的設計器互動代碼類(TestUserControl)裡面,新增以下代碼,功能如圖所示。
9、現在在xaml裡面,設定Binding就不會提示錯誤了。
10、并且也可以直接設定值,效果同上面設定屬性以後直接寫值效果一樣。
11、在Login頁面的ViewModel裡面,新增屬性提供給雙向綁定使用。
12、設定MyText進行Binding到剛剛寫的ViewModel的屬性TestText上。
13、運作效果如下圖所示,說明雙向綁定成功了。
14、接下來對使用者控件設定單擊事件的雙向綁定。先設定Command有關的依賴屬性。
15、一些有關方法和其他的屬性設定,就不做過多介紹了,看圖說話。
16、然後是關鍵的一步,需要設定單機事件與Command屬性關聯。當然,Command是命名得來的,是以也可以使用其他的命名,也都是OK的,不用在意這些細節,隻是預設情況下,單擊都喜歡用Command。如果自帶的控件也沒有輕按兩下、右鍵等雙向綁定,也可以通過設定依賴屬性來實作。
17、在ViewModel裡面定義單擊事件以及有關執行的方法。方法為一個彈出消息框。
18、使用Command進行綁定事件名稱。
19、運作,并單擊實心圓的效果,并彈出提示框,說明單擊事件通過依賴屬性進行設定成功。
20、接下來測試一下帶參數的事件。在viewmodel裡面,對剛才無參數的事件,改為帶一個string參數的。
21、在xaml裡面,傳入一個字元串參數,就叫 Hello world
22、運作,并點選實心圓後效果如圖所示,說明帶參數也是OK的。
23、其他套路如出一轍,大佬們可以自行嘗試,例如通過設定背景依賴屬性,變更實心圓的背景,而不是整個使用者控件(正方形)的背景。這部分本來也要寫一個給大佬們壓壓驚,由于時間關系,大佬們可以自己嘗試玩一下。
提示:背景 Background是系統自帶的,是以需要new。通過屬性依賴進行更改圓的顔色,而不是背景色。有興趣的大佬或者需要學習的,可以動手玩一玩,加深印象。
以上就是該文章的全部内容,如果對你有幫助,歡迎大佬點贊、留言與轉發。如需轉發,請注明我的部落格出處:
https://www.cnblogs.com/weskynet/p/16290422.html
如果有知識分享、技術讨論的熱情,可通過原文連結(以上部落格園連結為原文連結,CSDN為自動同步連結,其他均為盜版連結) 的文章最下方,點選加入.NET 讨論QQ群。或者也可以掃下方我的微信二維碼頭像加我私人微信,然後我可以拉到我的微信交流群一起學習和技術了解,也都是OK的,歡迎大佬們來玩。
私人微信:
WeskyNet001
以下是有關最終的源代碼:
TestUserControl:
<Grid>
<Viewbox Stretch="Fill">
<Canvas Width="200" Height="200">
<Ellipse Name="rect3" Width="200" Height="200" Stroke="Orange" StrokeThickness="100" >
</Ellipse>
</Canvas>
</Viewbox>
<TextBlock x:Name="TextName" Text="123" VerticalAlignment="Center" HorizontalAlignment="Center"></TextBlock>
</Grid>
public partial class TestUserControl : UserControl
{
public TestUserControl()
{
InitializeComponent();
}
public static readonly DependencyProperty MyTextProperty =
DependencyProperty.Register("MyText", typeof(String), typeof(TestUserControl),
new PropertyMetadata((String)null, new PropertyChangedCallback(TextChanged)));
private static void TextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
TestUserControl control = d as TestUserControl;
if (control != null)
{
String oldText = e.OldValue as String; // 舊的值
String newText = e.NewValue as String; // 更新的新的值
control.UpdateMyText(newText);
}
}
private void UpdateMyText(string newValue)
{
this.TextName.Text = newValue;
}
[Bindable(true)]
[Category("Appearance")] // using System.ComponentModel;
public string MyText
{
get
{
return (String)GetValue(MyTextProperty);
}
set
{
SetValue(MyTextProperty, value);
}
}
public static readonly DependencyProperty CommandProperty =
DependencyProperty.Register("Command", typeof(ICommand), typeof(TestUserControl),
new PropertyMetadata((ICommand)null, new PropertyChangedCallback(CommandChanged)));
public static readonly DependencyProperty CommandParameterProperty =
DependencyProperty.Register("CommandParameter", typeof(object), typeof(TestUserControl));
public static readonly DependencyProperty CommandTargetProperty =
DependencyProperty.Register("CommandTarget", typeof(IInputElement), typeof(TestUserControl));
private static void CommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
TestUserControl control = d as TestUserControl;
if (control != null)
{
ICommand oldCommand = e.OldValue as ICommand;
ICommand newCommand = e.NewValue as ICommand;
control.UpdateCommand(oldCommand, newCommand);
}
}
private void UpdateCommand(ICommand oldCommand, ICommand newCommand)
{
if (oldCommand != null)
{
oldCommand.CanExecuteChanged -= CanExecuteChanged;
}
if (newCommand != null)
{
newCommand.CanExecuteChanged += CanExecuteChanged;
}
}
private void CanExecuteChanged(object sender, EventArgs e)
{
RoutedCommand command = this.Command as RoutedCommand;
if (command != null)
{
this.IsEnabled = command.CanExecute(CommandParameter, CommandTarget);
}
else if (this.Command != null)
{
this.IsEnabled = this.Command.CanExecute(CommandParameter);
}
}
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
public object CommandParameter
{
get { return GetValue(CommandParameterProperty); }
set { SetValue(CommandParameterProperty, value); }
}
public IInputElement CommandTarget
{
get { return (IInputElement)GetValue(CommandTargetProperty); }
set { SetValue(CommandTargetProperty, value); }
}
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
RoutedCommand command = Command as RoutedCommand;
if (command != null)
command.Execute(CommandParameter, CommandTarget);
else if (Command != null)
this.Command.Execute(CommandParameter);
}
}
}
LoginViewModel:
public class LoginViewModel: BindableBase
{
public LoginViewModel()
{
}
public string _testText = "999";
public string TextText
{
get { return _testText; }
set { SetProperty(ref _testText, value); }
}
private DelegateCommand<string> _testCommand;
public DelegateCommand<string> TestCommand
{
get
{
if (_testCommand == null)
{
_testCommand = new DelegateCommand<string>(ExecuteTestCommand);
}
return _testCommand;
}
}
private void ExecuteTestCommand(string value)
{
MessageBox.Show(value);
}
}
歡迎加入QQ群:
群号:1079830632