How to set the Content of repeated buttons in a grid based from a data source

dipique

Member
Joined
Oct 22, 2014
Messages
7
Programming Experience
1-3
I am new to WPF and am having difficulty accomplishing something that is probably pretty simple.

What my app does (or is supposed to do)
Starting with a string of special characters for a language (Spanish in this case: "?????????"), my app is to display a button for each character so the user can press the button and have the character inserted in whatever app they are in. Sort of like a universal character insert toolbar.

My progress so far
I have buttons that display in a grid, and when you click a given button, a message box appears with the character associated with that button (example, "?"). The buttons are created dynamically from the data model.

My problem
I can't figure out how to set the button caption/content to the same character it displays when clicked. My current XAML for the button looks like this:

C#:
                            <Button Content="{Binding DataContext.Data, RelativeSource={RelativeSource AncestorType=ItemsControl}}"                                    Command="{Binding DataContext.InsertChar, RelativeSource={RelativeSource AncestorType=ItemsControl}}"                                    
                                    CommandParameter="{Binding}"/>

The data inside the model is as follows:

C#:
            Data = new ObservableCollection<string>(Characters);

The output is that each button has the caption of "(Collection)" instead of the appropriate string value.

Bonus Problem :)
All the buttons are currently laid out vertically, but I'd actually like to set a maximum number of buttons horizontally and have them laid out in a 2d grid. Any pointers on that would be awesome.

The Full Code
MainWindow.xaml.cs:
C#:
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = new CharacterDataModel();     
        }
    }
MainWindow.xaml:
C#:
Window x:Class="Special_Character_Inserter.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Special Character Inserter" Height="300" Width="300">
    <DockPanel>
        <ItemsControl ItemsSource="{Binding Data}" Height="248" VerticalAlignment="Bottom">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Border  BorderBrush="Black" Background="Gainsboro" BorderThickness="1" Margin="2">
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto"/>
                                <RowDefinition Height="Auto"/>
                            </Grid.RowDefinitions>


                            <Grid.ColumnDefinitions>
                                <ColumnDefinition/>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="Auto"/>
                            </Grid.ColumnDefinitions>
                            <Button Content="{Binding DataContext.Data, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
                                    Command="{Binding DataContext.InsertChar, RelativeSource={RelativeSource AncestorType=ItemsControl}}"                                    
                                    CommandParameter="{Binding}"/>
                        </Grid>
                    </Border>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
            <ItemsControl.Template>
                <ControlTemplate TargetType="ItemsControl">
                    <ScrollViewer CanContentScroll="True">
                        <Grid Height="248" Width="275">
                            <ItemsPresenter Grid.RowSpan="5" Grid.Row="5" Grid.ColumnSpan="5" Grid.Column="5"/>
                        </Grid>
                    </ScrollViewer>
                </ControlTemplate>
            </ItemsControl.Template>


            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <VirtualizingStackPanel/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
    </DockPanel>
</Window>
And the Data Model and helper classes, CharacterDataModel.cs:
C#:
    class CharacterDataModel
    {
        const string csCharacters = "?????????";


        /// <summary>
        /// Fill character array with upper and lower versions of each character
        /// </summary>
        private string[] GetSpecialCharsFromString(string chars)
        {
            string[] RetVal = new string[chars.Length * 2];
            for (int i = 0; i < chars.Length; i++)
            {
                string lowerChar = chars[i].ToString().ToLower();
                RetVal[i * 2] = lowerChar;
                string upperChar = lowerChar.ToUpper();
                if (lowerChar != upperChar)
                    RetVal[i * 2 + 1] = upperChar;
            }
            return RetVal;
        }


        public Command<string> InsertChar { get; set; }


        public ObservableCollection<string> Data { get; set; }


        public CharacterDataModel()
        {
            string[] Characters = GetSpecialCharsFromString(csCharacters);
            Data = new ObservableCollection<string>(Characters);
            InsertChar = new Command<string>(ExecuteCommand);
        }


        private void ExecuteCommand(string data)
        {
            MessageBox.Show(data);
        }
    }


    public class Command : ICommand
    {
        public Action Action { get; set; }


        public string DisplayName { get; set; }


        public void Execute(object parameter)
        {
            if (Action != null)
                Action();
        }


        public bool CanExecute(object parameter) => IsEnabled;


        private bool _isEnabled = true;
        public bool IsEnabled
        {
            get { return _isEnabled; }
            set
            {
                _isEnabled = value;
                if (CanExecuteChanged != null)
                    CanExecuteChanged(this, EventArgs.Empty);
            }
        }


        public event EventHandler CanExecuteChanged;


        public Command(Action action)
        {
            Action = action;
        }
    }


    public class Command<T> : ICommand
    {
        public Action<T> Action { get; set; }


        public void Execute(object parameter)
        {
            if (Action != null && parameter is T)
                Action((T)parameter);
        }


        public bool CanExecute(object parameter)
        {
            return IsEnabled;
        }


        private bool _isEnabled = true;
        public bool IsEnabled
        {
            get { return _isEnabled; }
            set
            {
                _isEnabled = value;
                if (CanExecuteChanged != null)
                    CanExecuteChanged(this, EventArgs.Empty);
            }
        }


        public event EventHandler CanExecuteChanged;


        public Command(Action<T> action)
        {
            Action = action;
        }
    }
Thank you!
 
Top Bottom