【问题标题】:WPF Data Templates and ButtonsWPF 数据模板和按钮
【发布时间】:2013-03-13 21:17:25
【问题描述】:

注意:我使用的是 Visual Studio 2012

我有以下DataTemplate(注意:有一个TextBlock和Button)

<DataTemplate DataType="{x:Type ctlDefs:myButton}">
    <StackPanel>
        <TextBlock Text="{Binding LabelText}" Margin="10,0,10,0"/>

        <Button Content="{Binding LabelText}" Margin="0,0,10,0" 
            Width="{Binding ButtonWidth}" 
            Height="35"
            Command="{Binding ButtonCommand}" 
            Visibility="Visible"                    
            />
    </StackPanel>
</DataTemplate>

我的屏幕正在动态地将 myButton 的控件添加到 Items Control

 <ItemsControl ItemsSource="{Binding CommandButtons, Mode=OneWay}"
               FlowDirection="LeftToRight"
               DockPanel.Dock="Right"
              >

第一次渲染视图时,每个按钮都会显示 Textblock,但 Button 本身不会。如果我隐藏视图然后再次显示它,按钮有时会出现(如果 CommandButtons 列表没有改变,如果它改变了,它永远不会显示)。

渲染视图后,我查看了输出窗口,没有出现绑定错误。

我错过了什么。

【问题讨论】:

  • 不绑定Button的Width是否也会出现这种情况? ButtonWidth 是否实现 INotifyPropertyChanged?
  • 是的。如果我删除 ButtonWidth,它的功能相同。从我使用 WPF 检查器可以看出,按钮看起来就在那里(为它保留了空间),并且所有属性从第一次加载到第二次加载时都匹配。

标签: wpf datatemplate


【解决方案1】:

我已经创建了一个快速应用程序来处理您的示例代码,并且该视图似乎没有任何问题。下面是运行时的样子。

我已将我的代码包含在下面以防万一。 注意:为简洁起见,我没有添加真正的 ICommand 对象,并且我不小心将 MyButton 类命名为大写 M 而不是像您的示例那样小 m

ViewModelBase.cs

public abstract class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        this.OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
    }

    protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        var handler = this.PropertyChanged;
        if (handler != null)
        {
            handler(this, e);
        }
    }
}

public class MainWindowViewModel : ViewModelBase
{
    public MainWindowViewModel()
    {
        this.CommandButtons = new ObservableCollection<MyButton>();
    }
    public ObservableCollection<MyButton> CommandButtons { get; private set; }
}

App.xaml.cs

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        var mainvm = new MainWindowViewModel();
        var window = new MainWindow
        {
            DataContext = mainvm
        };
        window.Show();

        mainvm.CommandButtons.Add(new MyButton { ButtonWidth = 50, LabelText = "Button 1" });
        mainvm.CommandButtons.Add(new MyButton { ButtonWidth = 50, LabelText = "Button 2" });
        mainvm.CommandButtons.Add(new MyButton { ButtonWidth = 50, LabelText = "Button 3" });
    }
}

MainWindow.xaml

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:ctlDefs="clr-namespace:WpfApplication1"
    Title="MainWindow" Height="350" Width="525">
<Window.Resources>
    <DataTemplate DataType="{x:Type ctlDefs:MyButton}">
        <StackPanel>
            <TextBlock Text="{Binding LabelText}" Margin="10,0,10,0"/>

            <Button Content="{Binding LabelText}" Margin="0,0,10,0" 
                    Width="{Binding ButtonWidth}" 
                    Height="35"
                    Command="{Binding ButtonCommand}" 
                    Visibility="Visible"                    
        />
        </StackPanel>
    </DataTemplate>
</Window.Resources>
<Grid>
    <ItemsControl ItemsSource="{Binding CommandButtons, Mode=OneWay}"
           FlowDirection="LeftToRight"
           DockPanel.Dock="Right"
          />
</Grid>

MyButton.cs

public class MyButton : ViewModelBase
{
    private string _labelText;

    public string LabelText
    {
        get { return this._labelText; }
        set { this._labelText = value; this.OnPropertyChanged("LabelText"); }
    }

    private double _buttonWidth;

    public double ButtonWidth
    {
        get { return _buttonWidth; }
        set { _buttonWidth = value; this.OnPropertyChanged("ButtonWidth"); }
    }

    private ICommand _buttonCommand;

    public ICommand ButtonCommand
    {
        get { return _buttonCommand; }
        set { _buttonCommand = value; this.OnPropertyChanged("ButtonCommand"); }
    }
}

【讨论】:

  • 我有你的代码在我的机器上工作,命令按钮上的 ObservableCollection 和 List 有一些不同); ICommand 与 DelegateCommand。我进行了这些更改,但我的仍然无法正常工作。我在想还有其他事情发生。感谢您帮助验证此方法是否有效。我将尝试简化我的大型项目,看看我能得到什么。我接受了这个作为答案,因为它是“应该”的工作方式。
  • 无法点击向上箭头,因为我的代表不够高 :-(
  • 终于把范围缩小了。在我的样式文件中,有这个条目&lt;Style TargetType="{x:Type Button}"&gt; &lt;Setter Property="FocusVisualStyle" Value="{DynamicResource NuclearButtonFocusVisual}" /&gt;&lt;Setter Property="Background" Value="{DynamicResource NormalBrush}" /&gt; &lt;Setter Property="Foreground" Value="{DynamicResource TextBrush}" /&gt; &lt;Setter Property="BorderBrush" Value="{DynamicResource NormalBorderBrush}" /&gt; &lt;!--&lt;Setter Property="Template" Value="{DynamicResource ButtonTemplate}" /&gt;--&gt; &lt;/Style&gt; 注释掉的行是问题,但不知道为什么
  • 很高兴你成功了!您需要检查 ButtonTemplate 的定义,看看是否包含了您需要的所有 PART 定义。委托命令也可以正确使用,我通常将它连接到我的构造函数中。 this.Command = new DelegateCommand(o => this.MyMethod();
猜你喜欢
  • 2013-04-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-01
  • 2011-05-08
  • 1970-01-01
  • 2022-01-22
  • 1970-01-01
相关资源
最近更新 更多