Я достиг своего умственного барьера и не в состоянии понять это. Я уверен, что упускаю что-то простое, но я застрял. Код ниже - это минимальный код, необходимый для решения моей проблемы, но он далек от моего производственного кода.
Настройка:
У меня есть окно WPF с DataGrid элемент управления, связанный с бизнес-объектом , который включает набор активов . Для каждого актива мне нужно отобразить пользовательский элемент управления (SpecialButton), который visibility определяется на основе нескольких свойств объекта актива . Когда я нажимаю кнопку ( в моем примере, у меня есть дополнительная кнопка, которая для простоты меняет свойства ), она изменяет свойство базового объекта актива, что должно скрывать элемент управления.
Задача
Я связываю свойство элемента управления пользователя ControlVisibility
со всем объектом актива {Binding .}
<local:SpecialButton x:Name="buttonOnEachRow" ControlId="{Binding Id}"
ControlVisibility="{Binding ., Converter={StaticResource MyConverter}}"/>
Когда я изменяю свойство объекта Объект актива PropertyA
Я ожидаю, что MyConverter
должен запуститься и изменить значение видимости, но этого не произойдет.
То, что я пробовал
Я пробовал так много вещей что я даже не помню Наиболее многообещающим кажется MultipleBinding
, но я не смог понять, как написать синтаксис для свойства ControlVisibility
. Я попытался установить некоторые параметры на элементе управления DataGrid
, изменив способ обновления user control
, но без vail.
В качестве обходного пути в своем рабочем коде я создал свойство fake
, которое выполняет logi c который в данный момент находится в конвертере и привязывает ControlVisibility
к свойству fake
. Это работает, но у меня есть совершенно не связанное свойство в моем объекте актива, которое существует только потому, что я не могу определить привязку.
Главное окно WPF
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
namespace MultiBindingProblem
{
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
var sut = new BusinessObject() { Caption = "This is the parent object", Assets = new List<Asset>()};
sut.Assets.Add(new Asset() { Name = "Asset 1", Id = 1 });
sut.Assets.Add(new Asset() { Name = "Asset 2", Id = 2 });
sut.Assets.Add(new Asset() { Name = "Asset 3", Id = 3 });
this.DataContext = sut;
}
public event PropertyChangedEventHandler PropertyChanged;
private void BtnCancel_Click(object sender, RoutedEventArgs e)
{
Close();
}
private void BtnChange_Click(object sender, RoutedEventArgs e)
{
((BusinessObject)this.DataContext).Assets[0].PropertyA = true;
//PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Assets"));
}
}
}
XAML btnChange
здесь для простоты. В моем производственном коде SpecialButton вызовет обновление свойства в моей модели представления
<Window x:Class="MultiBindingProblem.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MultiBindingProblem"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800" WindowStartupLocation="CenterScreen">
<Window.Resources>
<local:TestConverter x:Key="MyConverter" />
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*" />
<ColumnDefinition Width="0.5*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="*" />
<RowDefinition Height="100" />
</Grid.RowDefinitions>
<TextBlock x:Name="lblMainObject" Grid.ColumnSpan="2" Grid.Row="0" FontSize="25"
Text="{Binding Caption}" />
<Button x:Name="btnCancel" Content="Cancel" IsCancel="True" IsDefault="True" Grid.Row="2" Grid.Column="1" Click="BtnCancel_Click" />
<DataGrid x:Name="dgrData" Grid.Row="1" Grid.ColumnSpan="2" AutoGenerateColumns="False" CanUserAddRows="False"
ItemsSource="{Binding Assets, NotifyOnSourceUpdated=True}" >
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
<DataGridTemplateColumn Header="Action button" Width="100">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<!--
Here I bind to the whole 'Asset' object to be able to determine if the button should be
visible based on multiple properties. But changing a propety doesn't raise the converter.
I tried use multiple bindings but I was not able to figure out the syntax
-->
<local:SpecialButton x:Name="buttonOnEachRow"
ControlId="{Binding Id}"
ControlVisibility="{Binding ., Converter={StaticResource MyConverter}}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<Button x:Name="btnChange" Grid.Row="2" Grid.Column="0" Content="Change visibility of the first button" Click="BtnChange_Click" />
</Grid>
</Window>
Пользовательский элемент управления (SpecialButton)
using System.Windows;
using System.Windows.Controls;
namespace MultiBindingProblem
{
public partial class SpecialButton : UserControl
{
public SpecialButton()
{
InitializeComponent();
}
public static readonly DependencyProperty ControlIdProperty =
DependencyProperty.Register("ControlId", typeof(int),
typeof(SpecialButton));
public int ControlId
{
get { return (int)GetValue(ControlIdProperty); }
set { SetValue(ControlIdProperty, value); }
}
public static readonly DependencyProperty ControlVisibilityProperty =
DependencyProperty.Register("ControlVisibility", typeof(Visibility),
typeof(SpecialButton), new FrameworkPropertyMetadata(Visibility.Visible));
public Visibility ControlVisibility
{
get { return (Visibility)GetValue(ControlVisibilityProperty); }
set { SetValue(ControlVisibilityProperty, value); }
}
private void btnSpecialButton_Click(object sender, RoutedEventArgs e)
{
System.Windows.MessageBox.Show($"The id of the button: {((Button)sender).Tag.ToString()}");
}
}
}
XAML
<UserControl x:Class="MultiBindingProblem.SpecialButton"
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:MultiBindingProblem"
mc:Ignorable="d"
d:DesignHeight="45" d:DesignWidth="80"
x:Name="parent">
<Grid>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch" DataContext="{Binding ElementName=parent}">
<Button x:Name="btnSpecialButton" Content="Click Me" Click="btnSpecialButton_Click"
Tag="{Binding ControlId}"
Visibility="{Binding ControlVisibility}" />
</StackPanel>
</Grid>
</UserControl>
TestConverter
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace MultiBindingProblem
{
public class TestConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var asset = value as Asset;
if (asset == null) return Visibility.Hidden;
return !(asset.PropertyA || asset.PropertyB) ? Visibility.Visible : Visibility.Hidden;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
Вопрос
Можно ли как-нибудь использовать Multibinding
?
Или
Как сделать конвертер запустить, когда изменилось одно свойство объекта актива?