[英]Binding on DependencyProperty of custom User Control not updating on change
[英]Binding to dependencyproperty in user control and calling CanExecute on nested property change
我創建了一個用戶控件,它基本上包含一堆組合框,稱為 SearchParamsControl。 SearchParamsControl 包含在 SearchParams class 中設置所有內容所需的所有 UI 元素:
我的 SearchParamsControl:
/// <summary>
/// Interaction logic for SearchParamsControl.xaml
/// </summary>
public partial class SearchParamsControl : INotifyPropertyChanged
{
public SearchParamsControl()
{
InitializeComponent();
}
/// <summary>
/// Radius entries bound to combobox
/// </summary>
public Dictionary<double, string> RadiusEntries
{
get;
set;
} = new Dictionary<double, string>()
{
{0, "This area only" },
{ 0.25, "Within 1/4 mile" },
{ 0.5, "Within 1/2 mile" },
{ 1, "Within 1 mile" },
{ 3, "Within 3 miles" },
{ 5, "Within 5 miles" },
{ 10, "Within 10 miles" },
{ 15, "Within 15 miles" },
{ 20, "Within 20 miles" },
{ 30, "Within 30 miles" },
{ 40, "Within 40 miles" }
};
public Dictionary<PropertyTypeEnum, string> PropertyTypes => PropertyTypeDictionary;
/// <summary>
/// Prices bound to combo box
/// </summary>
public List<int> Prices
{
get;
set;
} = new List<int>()
{
0,
50000,
60000,
70000,
80000,
90000,
100000,
110000,
120000,
125000,
130000,
150000,
200000,
250000,
300000,
325000,
375000,
400000,
425000,
450000,
475000,
500000,
550000,
600000,
650000,
700000,
800000,
900000,
1000000,
1250000,
1500000,
1750000,
2000000,
2500000,
3000000,
4000000,
5000000,
7500000,
10000000,
15000000,
20000000
};
/// <summary>
/// Bedrooms bound to combobox
/// </summary>
public List<int> Bedrooms
{
get;
set;
} = new List<int>()
{
0,
1,
2,
3,
4,
5
};
public StringTrieSet SearchString
{
get
{
return RightMoveCodes.RegionTree;
}
}
public double Radius
{
get => SearchParams.Radius;
set
{
if (SearchParams.Radius != value)
{
SearchParams.Radius = value;
OnSearchParamsChanged();
}
}
}
public int MinBedrooms
{
get { return SearchParams.MinBedrooms; }
set
{
if (SearchParams.MinBedrooms != value)
{
SearchParams.MinBedrooms = value;
OnSearchParamsChanged();
}
}
}
public int MaxBedrooms
{
get { return SearchParams.MaxBedrooms; }
set
{
if (SearchParams.MaxBedrooms != value)
{
SearchParams.MaxBedrooms = value;
OnSearchParamsChanged();
}
}
}
public int MinPrice
{
get { return SearchParams.MinPrice; }
set
{
if (SearchParams.MinPrice != value)
{
SearchParams.MinPrice = value;
OnSearchParamsChanged();
}
}
}
public int MaxPrice
{
get { return SearchParams.MaxPrice; }
set
{
if (SearchParams.MaxPrice != value)
{
SearchParams.MaxPrice = value;
OnSearchParamsChanged();
}
}
}
public SortType SortType
{
get { return SearchParams.Sort; }
set
{
if (SearchParams.Sort != value)
{
SearchParams.Sort = value;
OnSearchParamsChanged();
}
}
}
public SearchParams SearchParams
{
get
{
SearchParams searchParams = (SearchParams)GetValue(SearchParamsProperty);
return searchParams;
}
set
{
SetValue(SearchParamsProperty, value);
}
}
// Using a DependencyProperty as the backing store for MySelectedItem. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SearchParamsProperty =
DependencyProperty.Register("SearchParams", typeof(SearchParams), typeof(SearchParamsControl), new PropertyMetadata(new SearchParams(), OnSearchParamsPropertyChanged));
public event PropertyChangedEventHandler PropertyChanged;
private static void OnSearchParamsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
SearchParamsControl c = d as SearchParamsControl;
if (c != null)
{
c.OnSearchParamsChanged();
}
}
private void OnSearchParamsChanged()
{
OnPropertyChanged(nameof(SearchParams));
}
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
還有 xml:
<UserControl x:Class="RightMoveApp.UserControls.SearchParamsControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:RightMoveApp.UserControls"
xmlns:System="clr-namespace:System;assembly=System.Runtime"
xmlns:StyleAlias="clr-namespace:RightMove;assembly=RightMove"
xmlns:viewModel="clr-namespace:RightMoveApp.ViewModel"
xmlns:dataTypes="clr-namespace:RightMove.DataTypes;assembly=RightMove"
xmlns:valueconverters="clr-namespace:RightMoveApp.UserControls.ValueConverters"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
x:Name="uc">
<UserControl.DataContext>
<viewModel:SearchParamsControlViewModel/>
</UserControl.DataContext>
<UserControl.Resources>
<ObjectDataProvider x:Key="dataFromEnum" MethodName="GetValues" ObjectType="{x:Type System:Enum}">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="dataTypes:SortType"/>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
<valueconverters:PropertyTypeConverter x:Key="PropertyTypeConverter" x:Shared="False"/>
<Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource ComboStyle}">
<Setter Property="Margin" Value="0,0,0,1"/>
</Style>
</UserControl.Resources>
<Grid x:Name="LayoutRoot">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Grid.Column="0" Grid.Row="0" Content="Search area"/>
<local:AutoCompleteComboBox Grid.Row="0" Grid.Column="1"
ItemsSource="{Binding ElementName=uc, Path=SearchString}"
SelectedValue="{Binding Path=RegionLocation, Mode=TwoWay}"/>
<Label Grid.Column="0" Grid.Row="1" Content="Search radius"/>
<ComboBox Template="{DynamicResource ComboBoxTemplate1}" Grid.Column="1" Grid.Row="1" Name="comboSearchRadius"
ItemsSource="{Binding ElementName=uc, Path=RadiusEntries}"
SelectedValuePath="Key"
SelectedValue="{Binding ElementName=uc, Path=Radius, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Value}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<Label Grid.Column="0" Grid.Row="2" Content="Price range (£)"/>
<Grid Grid.Column="1" Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ComboBox Grid.Column="0" Grid.Row="0" Name="comboMinPrice"
ItemsSource="{Binding ElementName=uc, Path=Prices}"
SelectedItem="{Binding ElementName=uc, Path=MinPrice, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<Label Grid.Column="1" Grid.Row="0" Content="to"/>
<ComboBox Grid.Column="2" Grid.Row="0" Name="comboMaxPrice"
ItemsSource="{Binding ElementName=uc, Path=Prices}"
SelectedItem="{Binding ElementName=uc, Path=MaxPrice}">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Grid>
<Label Grid.Column="0" Grid.Row="3" Content="No. of bedrooms"/>
<Grid Grid.Column="1" Grid.Row="3">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ComboBox Grid.Column="0" Grid.Row="0" Name="comboMinBedrooms"
ItemsSource="{Binding ElementName=uc, Path=Bedrooms}"
SelectedItem="{Binding ElementName=uc, Path=MinBedrooms, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<ComboBox Grid.Column="3" Grid.Row="0" Name="comboMaxBedrooms"
ItemsSource="{Binding ElementName=uc, Path=Bedrooms}"
SelectedItem="{Binding ElementName=uc, Path=MaxBedrooms, Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<Label Grid.Column="1" Grid.Row="0" Content="to"/>
</Grid>
<Label Grid.Column="0" Grid.Row="4" Content="Sort Type"/>
<ComboBox Grid.Column="1" Grid.Row="4" Name="comboSort"
ItemsSource="{Binding Source={StaticResource dataFromEnum}}"
SelectedItem="{Binding ElementName=uc, Path=SortType, Mode=TwoWay}">
</ComboBox>
</Grid>
我想綁定到我的 MainWindow 中的 SearchParams 依賴屬性,其中包含 SearchParamsControl:
<GroupBox Grid.Column="0" Grid.Row="0" Header="Search Params" Panel.ZIndex="10">
<controls:SearchParamsControl x:Name="searchControl"
SearchParams="{Binding Path=SearchParams, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="{Binding Path=IsSearching, Converter={StaticResource BooleanToReverseConverter}}">
</controls:SearchParamsControl>
</GroupBox>
<Button x:Name="btnSearch" Grid.Column="0" Grid.Row="1"
Content="Search"
IsDefault="True"
Command="{Binding SearchAsyncCommand}"/>
此綁定工作正常。 但是,如您所見,我的 MainWindow 中有一個 Button,它連接到一個命令。 我想知道 SearchParams 中的屬性何時發生更改,以便我可以調用類似 SearchCommandAsync.RaiseCanExecuteChanged() 的內容,以便更新“搜索”按鈕的 state。 我該如何處理?
請注意,我不想使用以下注釋掉的代碼(來自我的 Command 類),我認為它確實有效,但我希望能夠通知 SearchParams 具有更改的屬性,因此我們需要調用 CanExecute再次:
//public event EventHandler CanExecuteChanged
//{
// add
// {
// CommandManager.RequerySuggested += value;
// }
// remove
// {
// CommandManager.RequerySuggested -= value;
// }
//}
public event EventHandler CanExecuteChanged;
public void RaiseCanExecuteChanged()
{
//CommandManager.InvalidateRequerySuggested();
if (CanExecuteChanged != null)
{
CanExecuteChanged(this, new EventArgs());
}
}
此外,我不想使用 PropertyChanged 事件處理程序修改 SearchParams(想象它是一個封閉的 class 庫,我無法修改它)。
如果我正確理解您的設置,則視圖上SearchParamsControl
的SearchParams
屬性應在控件屬性更改時設置視圖 model 的數據綁定SearchParams
源屬性。
然后,您可以在SearchParams
源屬性的設置器中引發該命令的CanExecuteChanged
方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.