【问题标题】:Failing To Display Only Available Items in View无法在视图中仅显示可用项目
【发布时间】:2012-10-15 11:44:45
【问题描述】:

我是一名 C++ 开发人员,最近转向 C#。我正在开发一个 WPF 应用程序,我需要在其中动态生成按钮、文本框等 Ui 组件。这就是我到目前为止所做的。

XAML 类:

<Grid Visibility="{Binding IsAvailable, Converter={StaticResource booltovisibility}}">
    <Grid.Resources>
        <convert:BooleanToVisibilityConverter x:Key="booltovisibility"/>
    </Grid.Resources>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="170" />
        <ColumnDefinition />
        <ColumnDefinition Width="130" />
        <ColumnDefinition Width="115" />
    </Grid.ColumnDefinitions>
    <Label Grid.Column="0" Content="{Binding ChannelName}" Height="25" Width="120" Name="VoltageLabel" Margin="20,0,0,0" VerticalAlignment="Center" HorizontalAlignment="Left" />
    <TextBox Grid.Column="1" Text="{Binding VoltageText}" Height="25" Width="65" Name="VoltageBox" Margin="0,0,80,0" VerticalAlignment="Center" HorizontalAlignment="Center" />
    <Button Grid.Column="1" Content="Set" CommandParameter="{Binding VoltageText}" Command="{Binding VoltageCommand}" Height="25" Width="65" Name="VoltageSetbtn" Margin="80,0,0,0" VerticalAlignment="Center" HorizontalAlignment="Center" />
    <Label Grid.Column="2" Content="{Binding CurrentText}"  Height="25" Width="40" Name="CurrentLabel" Margin="0,0,0,0" VerticalAlignment="Center" HorizontalAlignment="Center" />
    <ToggleButton Grid.Column="3" Content="On"  Height="25" Width="30" Name="VoltageToggleBtn" Margin="0,0,0,0" VerticalAlignment="Center" HorizontalAlignment="Center" />
</Grid>

<Button Content="Bavaria" Name="BavariaBtn" Click="BavariaBtn_Click" />

ViewModel 类:

public List<VoltageBoardChannel> channelList = null;       

    public List<VoltageBoardChannel> bavaria2Channels = new List<VoltageBoardChannel>
    {
         new VoltageBoardChannel { ChannelName = "VDD__MAIN", IsAvailable = true, VoltageText = String.Empty, VoltageCommand = m_voltageCommand },
         new VoltageBoardChannel { ChannelName = "VDD__IO__AUD", IsAvailable = true, VoltageText = String.Empty, VoltageCommand = m_voltageCommand },
         new VoltageBoardChannel { ChannelName = "VDD__CODEC__AUD", IsAvailable = true, VoltageText = String.Empty, VoltageCommand = m_voltageCommand},
         new VoltageBoardChannel { ChannelName = "VDD__DAL__AUD", IsAvailable = true, VoltageText = String.Empty, VoltageCommand = m_voltageCommand },
         new VoltageBoardChannel { ChannelName = "VDD__DPD__AUD", IsAvailable = true, VoltageText = String.Empty, VoltageCommand = m_voltageCommand },
         new VoltageBoardChannel { ChannelName = "VDD__PLL__AUD", IsAvailable = true, VoltageText = String.Empty, VoltageCommand = m_voltageCommand },        
         new VoltageBoardChannel { ChannelName = "", IsAvailable = false, VoltageText = String.Empty, VoltageCommand = m_voltageCommand },
         new VoltageBoardChannel { ChannelName = "", IsAvailable = false, VoltageText = String.Empty, VoltageCommand = m_voltageCommand }
    };

    private ICommand m_voltageCommand;        

    public List<VoltageBoardChannel> bavaria1Channels = new List<VoltageBoardChannel>
    {
         new VoltageBoardChannel { ChannelName = "", IsAvailable = false, VoltageText = String.Empty, VoltageCommand = m_voltageCommand },
         new VoltageBoardChannel { ChannelName = "", IsAvailable = false, VoltageText = String.Empty, VoltageCommand = m_voltageCommand }
         new VoltageBoardChannel { ChannelName = "VDD__MAIN", IsAvailable = true, VoltageText = String.Empty, VoltageCommand = m_voltageCommand },
         new VoltageBoardChannel { ChannelName = "VDD__IO", IsAvailable = true, VoltageText = String.Empty, VoltageCommand = m_voltageCommand },
         new VoltageBoardChannel { ChannelName = "VDD__CODEC", IsAvailable = true, VoltageText = String.Empty, VoltageCommand = m_voltageCommand },
         new VoltageBoardChannel { ChannelName = "VDD__LDO", IsAvailable = true, VoltageText = String.Empty, VoltageCommand = m_voltageCommand },
         new VoltageBoardChannel { ChannelName = "VDD__AMP", IsAvailable = true, VoltageText = String.Empty, VoltageCommand = m_voltageCommand }             
    };            

    public VoltageViewModel()
    {
        channelList = new List<VoltageBoardChannel>(0);
        channelList = bavaria1Channels;            
        m_voltageCommand = new DelegateVoltageCommand(x => SetCommandExecute(x));
    }

    public List<VoltageBoardChannel> VoltageChannelList
    {
        get 
        { 
            return channelList; 
        }

        set
        { 
            channelList = value;
            OnPropertyChanged("ChannelList");
        }
    }        

    public void SetCommandExecute(object voltageText)
    {
        Debug.WriteLine(voltageText);
    }

模型类:

private string mChannelName;
    public string ChannelName
    {
        get; set;
    }

    private bool mIsAvailable;
    public bool IsAvailable
    {
        get; set;
    }

    string voltageText = string.Empty;
    public string VoltageText
    {
        get; set;
    }

    string currentText = "0 V";
    public string CurrentText
    {
        get; set;
    }

    public ICommand VoltageCommand { get; set; }

XAml.cs:

 VoltageViewModel mVoltageViewModel = new VoltageViewModel();

    public VoltageView()
    {
        InitializeComponent();
        this.DataContext = mVoltageViewModel;

        OnChildAdd();
    }
public void OnChildAdd() //Constructor
    {   
        VoltageViewModel mVoltageViewModel = new VoltageViewModel();         
        foreach (VoltageBoardChannel mVoltageChannelViewModel in mVoltageViewModel.VoltageChannelList)
        {
            VoltageChannelView mVoltageChannelView = new VoltageChannelView();
            mVoltageChannelView.Margin = new Thickness(2);
            mVoltageChannelView.ChannelInfo = mVoltageChannelViewModel;
            // Some Code
        }
    }

这里显示了 Bavaria 1 的所有频道,甚至是 available = false 的频道。因此,当它为 false 时,它​​会显示文本框、按钮、标签和切换按钮。频道名称是“”。我想实现以下目标:

我这里有 2 个频道,bavaria 1 和 bavaria 2。 启动时 bavaria1 已经显示。在这里,我想检查可用频道并仅在启动时将这些频道添加到我的视图中,即应显示available = true,而当available = false 时,不应显示相应的元素。目前,即使available = false 也会显示按钮、文本框、切换按钮,但标签除外(频道名称将为“”)。我怎样才能做到这一点?

【问题讨论】:

  • 您能展示您的完整视图 XAML 吗?上面的 XAML 似乎只是单个元素的代码,而不是问题所在的周围视图的代码。
  • channelList = new List(0);频道列表=巴伐利亚1频道;这是一些奇怪的代码。你不需要“新”一个列表,你也会分配一些完全不同的东西。那是“草率”的内存管理。
  • @Akku:更新了 xaml。检查
  • 不知道 Grid 的 boolToVisibilityConverter 资源是否与静态资源冲突。我只会使用静态的并在 App.xaml 文件中定义它。如果那不能解决它,我想知道 Grid 应该如何知道它的模型对象是哪个。您不应该在某处将 Grid 的 DataContext 设置为当前通道吗?无论如何我在代码中看不到这一点,并且网格也没有命名,因此请确保(调试器)DataContext 设置正确。此外,我同意 CodingBarfield 以一种非常奇怪的方式构建代码,这可能是我们尚未找到修复的原因。
  • @Akku:是的,由于 Grid.Resources,我收到了错误消息。此电压等级是用户控件,而不是窗口。还有其他方法可以完成吗?另外我更新了 xaml.cs 类 :) 我怎样才能完成这个可用性?

标签: c# wpf button mvvm viewmodel


【解决方案1】:

要使用布尔绑定在 XAML 中隐藏元素,您需要对其进行转换,因为元素的 Visibility 属性不是布尔字段。

<ListBox ItemsSource="{Binding VoltageChannelList}">
  <ListBox.Resources>
    <BooleanToVisibilityConverter x:Key="booltovisibility"/>
  </ListBox.Resources>
  <Grid Visibility="{Binding IsAvailable,
                     Converter={StaticResource booltovisibility}}">
     <!-- controls -->
  </Grid>
</ListBox>

使用默认的BooleanToVisibility 转换器。


话虽如此,您可能应该将 VoltageChannelList 更改为 ObservableCollection,以便在插入或删除项目时,更改会反映到您的视图中。

另请注意,当您使用自动属性时,您不会创建支持字段

private bool mIsAvailable; // this is not used by the property below
public bool IsAvailable { get; set; }

使用此代码时,mIsAvailable 永远不会从对 IsAvailable 的调用中返回,因为它会创建自己的支持字段。

【讨论】:

  • 不需要定义BooleanToVisibilityConverter,可以使用默认实现msdn.microsoft.com/en-us/library/…
  • @Patrick:嘿,兄弟,它在我的 xaml 文件中引发了异常。 'Provide value on 'System.Windows.StaticResourceExtension' threw an exception.' 我已经更新了 xaml。检查它是否正确?
  • 已解决问题 :) 感谢您的帮助 :)
【解决方案2】:

你可以像这样创建一个属性:

List<VoltageChannel> AvailableChannels {
  get
  {
     var returned = new List<VoltageChannel>();
     foreach (VoltageChannel vc in VoltageChannelList)
     {
        if (vc.IsAvailable)
          returned.add(vc);
     }
     return vc;
  }
}

然后,将您的视图绑定到此属性,可能使用像这样的 ItemsControl:

<ItemsControl Name="_itemsControl"  ItemsSource="{Binding AvailableChannels}">
  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate><WrapPanel />
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      ... (your XAML to show the channels) ...
    </DataTemplate>
  </ItemsControl.ItemTemplate>
</ItemsControl>

(没有测试你的代码)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-09
    • 2010-12-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-12
    相关资源
    最近更新 更多