Search code examples
wpfdatatemplate

WPF Data Templates and Buttons


Note: I am using Visual Studio 2012

I have the following DataTemplate (note: there is a TextBlock and 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>

My screen is dynamically adding controls of myButton to an Items Control

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

The first time I render the view, the Textblock shows up for each button, but the Button itself does not. If I hide the view and then show it again, the button will appear sometimes (if the CommandButtons list does not change, if it changes, it never shows).

After rendering the view, I looked in the Output window and no binding errors.

What am I missing.


Solution

  • I've knocked up a quick application to work with your sample code and didn't seem to have any issues with the view. Below is what it looks like when run.

    Looks like this

    I've included my code below in case it helps. Note: I didn't add a real ICommand object for brevity and I accidentally named the MyButton class with capital M instead of small m like your example

    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"); }
        }
    }