我正在嘗試將 RadioButton 系結到ObservableCollection<Face>. 我已經做了幾個系結,它們都在作業。但是在那一個上,我無法理解出了什么問題。唯一不同的是,我嘗試為此使用轉換器。首先,我的 ObservableCollection 是 an ObservableCollection<int>,然后我將其更改為 an ObservableCollection<Face>,因為我認為問題是我無法系結 an ObservableCollection<int>,但沒有任何改變。
這是我的轉換器。我不想有一個 ConvertBack,但不能洗掉它?:
public class VisibleIfListIntContains : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (parameter == null)
{
return false;
}
ObservableCollection<int> listInt = (ObservableCollection<int>)value;
int value2 = System.Convert.ToInt32(parameter.ToString());
//bool? retour = listInt.Contains(value2);
return listInt.Contains(value2)
? Visibility.Visible
: Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
if ((bool)value == true)
{
return System.Convert.ToInt32(parameter);
}
else
{
return new List<int>();
}
}
}
然后是我系結的類:
public partial class Macro : INotifyPropertyChanged
{
private ObservableCollection<int> listFacesAllowed = new ObservableCollection<int>();
public ObservableCollection<int> ListFacesAllowed
{
get { return this.listFacesAllowed; }
set
{
this.listFacesAllowed = value;
this.NotifyPropertyChanged("ListFacesAllowed");
}
}
}
我這樣修改我的 ObservableCollection :
private void setAvailableFaces()
{
this.ListFacesAllowed.Clear();
if (this.gpProfil == "I" || this.gpProfil == "H" || this.gpProfil == "U")
{
this.ListFacesAllowed.Add(0);
this.ListFacesAllowed.Add(1);
this.ListFacesAllowed.Add(2);
}
else if (this.gpProfil == "L")
{
this.ListFacesAllowed.Add(0);
this.ListFacesAllowed.Add(2);
}
else if (this.gpProfil == "M")
{
this.ListFacesAllowed.Add(0);
this.ListFacesAllowed.Add(1);
this.ListFacesAllowed.Add(2);
this.ListFacesAllowed.Add(3);
}
if (this.type==1)
{
if (this.isTraversingMacro)
{
if (this.gpProfil == "M")
{
this.ListFacesAllowed.Remove(1);
this.ListFacesAllowed.Remove(3);
}
else if (gpProfil == "I" || gpProfil == "H" || gpProfil == "U")
{
this.ListFacesAllowed.Remove(1);
if (this.name != "MV002" && this.name != "MV000")
{
this.ListFacesAllowed.Remove(2);
}
}
}
}
this.NotifyPropertyChanged("ListFacesAllowed");
if (this.listFacesAllowed.Any() && !this.listFacesAllowed.Contains(this.face))
{
this.Face = this.listFacesAllowed[0];
}
}
ObservableCollection 被修改,但轉換器從未執行。
這是 XAML 代碼:
<DataTemplate x:Key="TemplateType1">
<Grid Background="{StaticResource WindowBackgroundColor}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="200"/>
</Grid.ColumnDefinitions>
<Grid Margin="10,10,20,10">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid Grid.RowSpan="2">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<ListView ItemsSource="{Binding}" SelectedItem="{Binding DataContext.SelectedMacro,
RelativeSource={RelativeSource AncestorType=Window},Mode=TwoWay}" Margin="3" Width="auto">
<ListView.View>
<GridView>
<GridViewColumn Header="{x:Static p:Resources.Name}" Width="auto" DisplayMemberBinding="{Binding Name}"/>
</GridView>
</ListView.View>
</ListView>
<Button Grid.Row="1" HorizontalAlignment="Left" Margin="3,10,3,3" Click="AddMacro_Click">
<Image Source="../img/image_add.png" Width="40"/>
</Button>
</Grid>
<Grid Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="20"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<CheckBox Grid.Row="0" IsChecked="{Binding DataContext.SelectedMacro.IsTraversingMacro, RelativeSource={RelativeSource AncestorType=Window},Mode=TwoWay}"
Content="{x:Static p:Resources.Traversing}"
Margin="3"/>
<RadioButton Grid.Row="2" IsChecked="{Binding DataContext.SelectedMacro.Face, RelativeSource={RelativeSource AncestorType=Window},Converter={StaticResource isIntEqual},ConverterParameter=0}"
Visibility="{Binding DataContext.SelectedMacro.ListFacesAllowed, RelativeSource={RelativeSource AncestorType=Window},Converter={StaticResource visibleIfListIntContains},ConverterParameter=0}"
Content="{x:Static p:Resources.Web}"
Margin="3"/>
<RadioButton Grid.Row="3" IsChecked="{Binding DataContext.SelectedMacro.Face, RelativeSource={RelativeSource AncestorType=Window},Converter={StaticResource isIntEqual},ConverterParameter=1}"
Visibility="{Binding DataContext.SelectedMacro.ListFacesAllowed, RelativeSource={RelativeSource AncestorType=Window},Converter={StaticResource visibleIfListIntContains},ConverterParameter=1}"
Content="{x:Static p:Resources.FlangeTop}"
Margin="3"/>
<RadioButton Grid.Row="4" IsChecked="{Binding DataContext.SelectedMacro.Face, RelativeSource={RelativeSource AncestorType=Window},Converter={StaticResource isIntEqual},ConverterParameter=2}"
Visibility="{Binding DataContext.SelectedMacro.ListFacesAllowed, RelativeSource={RelativeSource AncestorType=Window},Converter={StaticResource visibleIfListIntContains},ConverterParameter=2}"
Content="{x:Static p:Resources.FlangeBottom}"
Margin="3"/>
<RadioButton Grid.Row="5" IsChecked="{Binding DataContext.SelectedMacro.Face, RelativeSource={RelativeSource AncestorType=Window},Converter={StaticResource isIntEqual},ConverterParameter=3}"
Visibility="{Binding DataContext.SelectedMacro.ListFacesAllowed, RelativeSource={RelativeSource AncestorType=Window},Converter={StaticResource visibleIfListIntContains},ConverterParameter=3}"
Content="{x:Static p:Resources.WebBack}"
Margin="3"/>
</Grid>
<Grid Grid.Column="2" HorizontalAlignment="Right">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<RadioButton Visibility="{Binding DataContext.SelectedMacro.BottomChoice,
RelativeSource={RelativeSource AncestorType=Window}, Converter={StaticResource BoolToVisConverter}}"
Content="{x:Static p:Resources.Top}"
GroupName="radioGroup31" Margin="0,3,0,3"
IsChecked="{Binding DataContext.SelectedMacro.Bottom,
RelativeSource={RelativeSource AncestorType=Window},
Converter={StaticResource InverseBoolRadioConverter}}" />
<RadioButton Grid.Row="1" Visibility="{Binding DataContext.SelectedMacro.BottomChoice,
RelativeSource={RelativeSource AncestorType=Window}, Converter={StaticResource BoolToVisConverter}}"
Content="{x:Static p:Resources.Bottom}"
GroupName="radioGroup32" Margin="0,3,0,3"
IsChecked="{Binding DataContext.SelectedMacro.Bottom,
RelativeSource={RelativeSource AncestorType=Window}, Converter={StaticResource BoolRadioConverter}}" />
</Grid>
</Grid>
<Grid Grid.Column="1" Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Label Content="{Binding DataContext.SelectedMacro.Name,
RelativeSource={RelativeSource AncestorType=Window}}" HorizontalAlignment="Center" FontSize="30"/>
<Image Grid.Row="1" Width="250" Height="250" Source="{Binding DataContext.SelectedMacro.ImageName,
RelativeSource={RelativeSource AncestorType=Window}}"/>
</Grid>
<Grid Grid.Row="2" Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="80"/>
</Grid.ColumnDefinitions>
<Button Content="{x:Static p:Resources.Delete}" Click="DeleteMacro_Click" Margin="3" >
<Button.Style>
<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
<Style.Triggers>
<DataTrigger Binding="{Binding DataContext.SelectedMacro.Name,RelativeSource={RelativeSource AncestorType=Window}, Mode=OneWay}" Value="">
<Setter Property="Button.IsEnabled" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
<Button Content="{x:Static p:Resources.Change}" Grid.Column="2" Click="EditMacro_Click" Margin="3">
<Button.Style>
<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
<Style.Triggers>
<DataTrigger Binding="{Binding DataContext.SelectedMacro.Name,RelativeSource={RelativeSource AncestorType=Window}, Mode=OneWay}" Value="">
<Setter Property="Button.Content" Value="{x:Static p:Resources.Add}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</Grid>
</Grid>
<Grid Margin="20,10,10,10" Grid.Column="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<ItemsControl Grid.Column="0" ItemsSource="{Binding DataContext.SelectedMacro.ListParams,RelativeSource={RelativeSource AncestorType=Window}}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Margin="0,0,0,5" Height="30">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<Label Content="{Binding Name}" VerticalAlignment="Center"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<ItemsControl Grid.Column="1" ItemsSource="{Binding DataContext.SelectedMacro.ListParams,RelativeSource={RelativeSource AncestorType=Window}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Margin="0,0,0,5" Height="30">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<TextBox Grid.Column="1" Text="{Binding Valeur}" PreviewTextInput="CheckIsPositiveDouble" VerticalAlignment="Center" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Grid>
</DataTemplate>
模板中的所有系結都作業良好,除了那些DataContext.SelectedMacro.ListFacesAllowed
uj5u.com熱心網友回復:
據我了解,您需要檢查 Id 集合中是否存在 UI 元素 Id。如果它在那里,然后安裝它的可見性。
如果我理解正確,那么明顯的問題是您誤解了 Binding 的邏輯。
系結將在第一次加載時起作用,對于后續更新,您需要通知已發生更改。
而且由于您系結到整個集合并且需要全部檢查,因此當您更改其任何元素時,您需要替換集合實體。
因為否則系結將(有條件地)檢查它是否是集合的另一個實體。如果相同,它不會更新,即使集合的元素已經不同。
簡單的例子:
using Simplified;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Core2022.SO.SiegfriedV
{
public class IntsViewModel : BaseInpc
{
private HashSet<int> _numbers = new HashSet<int>(Enumerable.Range(0, 10));
public HashSet<int> Numbers { get => _numbers; private set => Set(ref _numbers, value); }
public IntsViewModel()
{
AddIntCommand = new RelayCommand<int>(num =>
{
HashSet<int> copy = new HashSet<int>(Numbers);
copy.Add(num);
Numbers = copy;
});
RemoveIntCommand = new RelayCommand<int>(num =>
{
HashSet<int> copy = new HashSet<int>(Numbers);
copy.Remove(num);
Numbers = copy;
});
}
public RelayCommand<int> AddIntCommand { get; }
public RelayCommand<int> RemoveIntCommand { get; }
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace Core2022.SO.SiegfriedV
{
[ValueConversion(typeof(ISet<int>), typeof(Visibility))]
public class VisibleIfListIntContains : IValueConverter
{
private static readonly Int32Converter converter = new Int32Converter();
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is not ISet<int> ints)
return DependencyProperty.UnsetValue;
if (parameter is not int num)
{
if (!converter.IsValid(parameter))
return DependencyProperty.UnsetValue;
num = (int)(converter.ConvertFrom(parameter) ?? throw new Exception("God knows what happened."));
}
return ints.Contains(num)
? Visibility.Visible
: Visibility.Collapsed;
}
// The reverse conversion in such logic, in principle, will not work,
// since it is impossible to replace the collection itself with a new instance from the converter.
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
private VisibleIfListIntContains() { }
public static VisibleIfListIntContains Instance { get; } = new VisibleIfListIntContains();
}
}
namespace Core2022.SO.SiegfriedV
{
// Helper class for automatically converting a string (TextBox.Text) to an integer.
public class DataProxy
{
public int Number { get; set; }
}
}
<Window x:Class="Core2022.SO.SiegfriedV.IntsWindow"
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:Core2022.SO.SiegfriedV"
mc:Ignorable="d"
Title="IntsWindow" Height="450" Width="800"
DataContext="{DynamicResource vm}">
<Window.Resources>
<local:IntsViewModel x:Key="vm"/>
<local:DataProxy x:Key="proxy"/>
</Window.Resources>
<UniformGrid Columns="2">
<UniformGrid HorizontalAlignment="Center" Columns="1">
<TextBlock Text="0" Visibility="{Binding Numbers, Converter={x:Static local:VisibleIfListIntContains.Instance}, ConverterParameter=0}" VerticalAlignment="Center"/>
<TextBlock Text="1" Visibility="{Binding Numbers, Converter={x:Static local:VisibleIfListIntContains.Instance}, ConverterParameter=1}" VerticalAlignment="Center"/>
<TextBlock Text="2" Visibility="{Binding Numbers, Converter={x:Static local:VisibleIfListIntContains.Instance}, ConverterParameter=2}" VerticalAlignment="Center"/>
<TextBlock Text="3" Visibility="{Binding Numbers, Converter={x:Static local:VisibleIfListIntContains.Instance}, ConverterParameter=3}" VerticalAlignment="Center"/>
<TextBlock Text="4" Visibility="{Binding Numbers, Converter={x:Static local:VisibleIfListIntContains.Instance}, ConverterParameter=4}" VerticalAlignment="Center"/>
<TextBlock Text="5" Visibility="{Binding Numbers, Converter={x:Static local:VisibleIfListIntContains.Instance}, ConverterParameter=5}" VerticalAlignment="Center"/>
<TextBlock Text="6" Visibility="{Binding Numbers, Converter={x:Static local:VisibleIfListIntContains.Instance}, ConverterParameter=6}" VerticalAlignment="Center"/>
<TextBlock Text="7" Visibility="{Binding Numbers, Converter={x:Static local:VisibleIfListIntContains.Instance}, ConverterParameter=7}" VerticalAlignment="Center"/>
<TextBlock Text="8" Visibility="{Binding Numbers, Converter={x:Static local:VisibleIfListIntContains.Instance}, ConverterParameter=8}" VerticalAlignment="Center"/>
<TextBlock Text="9" Visibility="{Binding Numbers, Converter={x:Static local:VisibleIfListIntContains.Instance}, ConverterParameter=9}" VerticalAlignment="Center"/>
</UniformGrid>
<UniformGrid Columns="1">
<TextBox VerticalAlignment="Center" Width="40" HorizontalContentAlignment="Center"
Text="{Binding Number, Source={StaticResource proxy}}"/>
<UniformGrid Columns="2" HorizontalAlignment="Center" VerticalAlignment="Top">
<Button Content="Add" Padding="15 5" Margin="10"
Command="{Binding AddIntCommand}"
CommandParameter="{Binding Number, Source={StaticResource proxy}}"/>
<Button Content="Remove" Padding="15 5" Margin="10"
Command="{Binding RemoveIntCommand}"
CommandParameter="{Binding Number, Source={StaticResource proxy}}"/>
</UniformGrid>
</UniformGrid>
</UniformGrid>
</Window>
使用了BaseInpc 和 RelayCommand 類。
PS如果我誤解了你的任務,請更詳細地解釋它對你很重要的細節。
與澄清問題有關的答案的補充
據我了解您的代碼,我的解釋可以這樣應用:
public partial class Macro : BaseInpc
{
private IEnumerable<int> _listFacesAllowed = Enumerable.Empty<int>();
public IEnumerable<int> ListFacesAllowed
{
get => _listFacesAllowed;
set => Set(ref _listFacesAllowed, value);
}
private void setAvailableFaces()
{
if (this.gpProfil == "I" || this.gpProfil == "H" || this.gpProfil == "U")
{
ListFacesAllowed = ListFacesAllowed.Concat(new int[] { 0, 1, 3 }).Distinct().ToArray();
}
else if (this.gpProfil == "L")
{
ListFacesAllowed = ListFacesAllowed.Concat(new int[] { 0, 2 }).Distinct().ToArray();
}
else if (this.gpProfil == "M")
{
ListFacesAllowed = ListFacesAllowed.Concat(new int[] { 0, 1, 2, 3 }).Distinct().ToArray();
}
if (this.type == 1)
{
if (this.isTraversingMacro)
{
if (this.gpProfil == "M")
{
ListFacesAllowed = ListFacesAllowed.Except(new int[] { 0, 3 }).Distinct().ToArray();
}
else if (gpProfil == "I" || gpProfil == "H" || gpProfil == "U")
{
if (this.name != "MV002" && this.name != "MV000")
{
ListFacesAllowed = ListFacesAllowed.Except(new int[] { 1, 2 }).Distinct().ToArray();
}
else
{
ListFacesAllowed = ListFacesAllowed.Except(new int[] { 1 }).Distinct().ToArray();
}
}
}
}
}
[ValueConversion(typeof(ISet<int>), typeof(Visibility))]
public class VisibleIfListIntContains : IValueConverter
{
private static readonly Int32Converter converter = new Int32Converter();
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is not IEnumerable<int> ints)
return DependencyProperty.UnsetValue;
if (parameter is not int num)
{
if (!converter.IsValid(parameter))
return DependencyProperty.UnsetValue;
num = (int)(converter.ConvertFrom(parameter) ?? throw new Exception("God knows what happened."));
}
return ints.Contains(num)
? Visibility.Visible
: Visibility.Collapsed;
}
// The reverse conversion in such logic, in principle, will not work,
// since it is impossible to replace the collection itself with a new instance from the converter.
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
private VisibleIfListIntContains() { }
public static VisibleIfListIntContains Instance { get; } = new VisibleIfListIntContains();
}
該方法的稍微更優化的實作:
private static readonly ReadOnlyCollection<int>
facesEmpty = Array.AsReadOnly(Array.Empty<int>()),
faces013 = Array.AsReadOnly(new int[] { 0, 1, 3 }),
faces02 = Array.AsReadOnly(new int[] { 0, 2 }),
faces0123 = Array.AsReadOnly(new int[] { 0, 1, 2, 3 }),
faces03 = Array.AsReadOnly(new int[] { 0, 3 }),
faces12 = Array.AsReadOnly(new int[] { 1, 2}),
faces1 = Array.AsReadOnly(new int[] { 1 });
private void setAvailableFaces()
{
IEnumerable<int> newlistFaces = this.gpProfil switch
{
"I" or "H" or "U" => faces013,
"L" => faces02,
"M" => faces0123,
_ => facesEmpty
};
if (newlistFaces != facesEmpty && this.type == 1 && this.isTraversingMacro)
{
newlistFaces = this.gpProfil switch
{
"M" => newlistFaces.Except(faces03),
"I" or "H" or "U" => this.name switch
{
"MV002" or "MV000" => newlistFaces.Except(faces1),
_ => newlistFaces.Except(faces12)
},
_=> newlistFaces
};
}
ListFacesAllowed = newlistFaces;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/516383.html
