【发布时间】:2020-03-09 22:20:49
【问题描述】:
我的申请如下:
型号:
贸易
观看次数:
TradeManagerView
TradeView
视图模型:
TradeManagerViewModel
TradeManagerView 有一个DataGrid,其ItemsSource 在TradeManagerViewModel 中设置为ObservableCollection<Trade>,其数据模板是TradeView 自定义用户控件。
Trade 模型有一个TradeDirection 属性,它可以是In 或Out。 TradeManagerViewModel 提供两组ObservableCollection<Button>,每个TradeDirection 一组。这些按钮由用户在运行时配置,因此不在 XAML 中创建它们。我正在努力将TradeView 中的ItemsControl 绑定到TradeManagerViewModel 中的按钮,因为它的数据上下文是Trade 的一个实例,它由DataGrid ItemsSource 提供。
我已经尝试了以下方法,但都没有成功。我正在使用 Caliburn.Micro,它在运行时将 View 的 DataContext 设置为 ViewModel。
<ItemsControl x:Name="TradeActions" ItemsSource="{Binding InboundTradeActions, ElementName=TradeManager}">
<ItemsControl x:Name="TradeActions" ItemsSource="{Binding InboundTradeActions, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}">
如前所述,我需要根据Trade.TradeDirection 绑定到正确的集合(即InboundTradeActions 或OutboundTradeActions),因此上述方法在任何情况下都不起作用。我不确定这在带有 DataTrigger 的 XAML 中是否最有效?或创建返回正确集合的第三个属性。但不知何故,该属性需要知道 TradeDirection 用于相对 TradeView 的 DataContext。
我希望这一切都有意义。如果没有请告诉我,我会修改它。
贸易类
internal class Trade : PropertyChangedBase
{
public enum Direction { In, Out };
private ObservableCollection<Button> tradeActions = new ObservableCollection<Button>();
public ObservableCollection<Button> TradeActions
{
get { return tradeActions; }
set
{
tradeActions = value;
NotifyOfPropertyChange();
}
}
public Direction TradeDirection
{
get { return tradeDirection; }
set
{
tradeDirection = value;
if (value == Direction.In)
{
InArrowVisibility = Visibility.Visible;
OutArrowVisibility = Visibility.Hidden;
}
else
{
InArrowVisibility = Visibility.Hidden;
OutArrowVisibility = Visibility.Visible;
}
NotifyOfPropertyChange();
}
}
public Visibility InArrowVisibility { get; set; }
public Visibility OutArrowVisibility { get; set; }
// Other properties removed to shorten
}
TradeManagerView
<Window x:Class="ExaltedTrade.Views.TradeManagerView"
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:ExaltedTrade.Views"
mc:Ignorable="d"
Title="Trade Manager" Height="450" Width="400"
WindowStartupLocation="Manual"
Style="{StaticResource TradeManagerWindow}"
Top="{Binding WindowTop, Mode=TwoWay}"
Left="{Binding WindowLeft, Mode=TwoWay}"
x:Name="TradeManager">
<Grid>
<DataGrid x:Name="ActiveTrades"
AutoGenerateColumns="False"
IsReadOnly="True"
HeadersVisibility="None"
GridLinesVisibility="None"
Style="{StaticResource TradeManagerDataGrid}"
CellStyle="{StaticResource TradeControlCell}"
ItemsSource="{Binding ActiveTrades}">
<DataGrid.Columns>
<DataGridTemplateColumn Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<local:TradeView /> <!-- This is the custom UserControl -->
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
贸易视图
我已经包含了 UserControl 的层次结构,但删除了任何多余的控件以缩短。
<UserControl x:Class="ExaltedTrade.Views.TradeView"
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:ExaltedTrade.Views"
mc:Ignorable="d"
d:DesignHeight="150" d:DesignWidth="500" Style="{StaticResource TradeView}">
<Grid>
<Expander x:Name="Expander" HorizontalAlignment="Stretch" Margin="0,0,0,0" VerticalAlignment="Top" IsExpanded="True">
<Expander.Header>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" /><!-- Player Name -->
<ColumnDefinition Width="14" /><!-- Trade Direction -->
<ColumnDefinition Width="1*" /><!-- Quantity -->
<ColumnDefinition Width="16" /><!-- Currency Icon -->
<ColumnDefinition Width="26" /><!-- Timer -->
<ColumnDefinition Width="26" /><!-- Invite -->
<ColumnDefinition Width="26" /><!-- Trade -->
<ColumnDefinition Width="26" /><!-- Kick -->
<ColumnDefinition Width="26" /><!-- Whisper -->
<ColumnDefinition Width="26" /><!-- Close -->
</Grid.ColumnDefinitions>
<!-- Some controls removed to shorten -->
</Expander.Header>
<Expander.Content>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="16" />
<ColumnDefinition Width="22" />
</Grid.ColumnDefinitions>
<!-- Some controls removed to shorten -->
<!-- BINDING IS HERE -->
<ItemsControl x:Name="TradeActions" Grid.Column="0" Grid.Row="1" ItemsSource="{Binding InboundTradeActions, ElementName=TradeManager}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Style="{StaticResource TradeActions}" IsItemsHost="True" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
</Expander.Content>
</Expander>
</Grid>
</UserControl>
TradeManagerViewModel
class TradeManagerViewModel : PropertyChangedBase, IHandle<string>
{
private ObservableCollection<Trade> activeTrades = new ObservableCollection<Trade>();
public ObservableCollection<Trade> ActiveTrades
{
get
{
return activeTrades;
}
set
{
activeTrades = value;
NotifyOfPropertyChange();
}
}
public static ObservableCollection<Button> InboundTradeActions { get; set; } = new ObservableCollection<Button>();
public static ObservableCollection<Button> OutboundTradeActions { get; set; } = new ObservableCollection<Button>();
public TradeManagerViewModel()
{
//TODO: Remove the test Trades
ObservableCollection<Trade> temp = new ObservableCollection<Trade> { new Trade("ExamplePlayer", Trade.Direction.In) };
temp.Add(new Trade("AnotherExamplePlayer", Trade.Direction.Out));
ActiveTrades = temp;
SetupTradeActions();
}
private void SetupTradeActions()
{
// TradeActions for inbound Trades
InboundTradeActions.Clear(); // Remove any existing TradeAction buttons just in case
foreach (TradeAction tAction in AppSettings.GetSingleton().InboundTradeActions)
{
Button action = new Button
{
Content = tAction.ButtonText,
//action.Command = ; //TODO: Need to implement an ICommand to link the method to the buttons
CommandParameter = tAction
};
InboundTradeActions.Add(action);
}
// TradeActions for outbound Trades
OutboundTradeActions.Clear(); // Remove any existing TradeAction buttons just in case
foreach (TradeAction tAction in AppSettings.GetSingleton().OutboundTradeActions)
{
Button action = new Button
{
Content = tAction.ButtonText,
//action.Command = ; //TODO: Need to implement an ICommand to link the method to the buttons
CommandParameter = tAction
};
OutboundTradeActions.Add(action);
}
}
}
【问题讨论】:
-
“
TradeManagerViewModel提供了两组ObservableCollection<Button>”——好吧,这就是你的问题所在。Button是一个视图对象。任何视图模型都不应该与一个视图模型相关。正确的做法是将视图模型中的按钮抽象为一些非视图类型的对象,并将 that 绑定到 XAML 中的某个视图,例如带有适当模板的ItemsControl。您提出的问题过于宽泛,但已经有很多类似的问题,以及您最喜欢的网络搜索引擎的发现示例。
标签: c# wpf mvvm data-binding caliburn.micro