0

I have a ComboBox:

        <ComboBox Height="25" Width="150"
                  Name="EnvironmentComboBox"
                  ItemsSource="{Binding Path=SourceList}"
                  SelectedIndex="{Binding Path=SourceIndex}"
                  SelectionChanged="EnvironmentComboBox_SelectionChanged">
        </ComboBox>

In the code-behind, I populate the SourceList:

        public MainWindow()
        {
            InitializeComponent();
            ConfigurationService.SetEnvironmentValues(ConfigurationService.DefaultEnvironment);
            
            DataContext = this;
            //SourceIndex = 0;
            List<ComboBoxItem> source = new List<ComboBoxItem>
            {
                //new ComboBoxItem  { Content = " - Select Environment - "},
                new ComboBoxItem  { Content = "PROD"},
                new ComboBoxItem  { Content = "CERT"},
                new ComboBoxItem  { Content = "DEV"},
            };
            SourceList = source;
        }

This was largely based on what I found here (including the _sourceIndex and _sourceList fields and corresponding properties): Setting a Combobox 's selected value without firing SelectionChanged event

I have a SelectionChanged event, which fires after ComboBox selection is changed:

        private void EnvironmentComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (!(SourceIndex == 0))
            {
                String env = ((ComboBoxItem)((ComboBox)sender).SelectedValue).Content.ToString();
                string message = $"Are you sure you want to change environment to {env}?\nAll unsaved work will be lost!";
                const string caption = "Change Environment?";
                MessageBoxResult userResponse = MessageBox.Show(message, caption,
                    MessageBoxButton.YesNo, MessageBoxImage.Warning);

                if (userResponse == MessageBoxResult.Yes)
                {
                    bool envChange = ConfigurationService.SetEnvironmentValues(env);
                    EnvironmentChangedMessage(envChange);
                }
                else
                {

                }
            }
        }

There are really two issues here.

First, the SelectionChanged event appears to run upon the app starting, which I thought doing the data binding would solve (and it doesn't). So then I thought, I'll add a " - Select Environment - " ComboBoxItem (which you can see commented out) and then have that condition !(SourceIndex == 0) to prevent the code that switches the environment in my ConfigurationService class when that "dummy" value is selected. However, I'd really just like PROD to load in ConfigurationService class, and that to also be the selected index when the app starts up. So then I'm stuck with getting a MessageBox before the app has started, or PROD not changing becasue it is then equal to index 0.

Second, when the user clicks "No" on the MessageBox, I want to revert the value of the selected combo box item to what it was originally. I reviewed this: WPF ComboBox SelectedItem - change to previous value, but I am quite unsure how to implement this in my proof-of-concept. Do I have the setter mentioned there in my SourceIndex setter? If so, where does CancelChange() in my case?

I'd appreciate any help on these two questions.

JD136
  • 113
  • 9

3 Answers3

1

To prevent default values, usally I use a simple boolean variable (Is_Loaded) as follows

 bool Is_Loaded=false;
 public MainWindow()
    {
        InitializeComponent();
        ConfigurationService.SetEnvironmentValues(ConfigurationService.DefaultEnvironment);
        
        DataContext = this;
        //SourceIndex = 0;
        List<ComboBoxItem> source = new List<ComboBoxItem>
        {
            //new ComboBoxItem  { Content = " - Select Environment - "},
            new ComboBoxItem  { Content = "PROD"},
            new ComboBoxItem  { Content = "CERT"},
            new ComboBoxItem  { Content = "DEV"},
        };
        SourceList = source;

       //---------------------
       Is_Loaded=true;
    }



private void EnvironmentComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (!Is_Loaded){ return;}
        //================
        if (!(SourceIndex == 0))
        {
            String env = ((ComboBoxItem)((ComboBox)sender).SelectedValue).Content.ToString();
            string message = $"Are you sure you want to change environment to {env}?\nAll unsaved work will be lost!";
            const string caption = "Change Environment?";
            MessageBoxResult userResponse = MessageBox.Show(message, caption,
                MessageBoxButton.YesNo, MessageBoxImage.Warning);

            if (userResponse == MessageBoxResult.Yes)
            {
                bool envChange = ConfigurationService.SetEnvironmentValues(env);
                EnvironmentChangedMessage(envChange);
            }
            else
            {

            }
        }
    }
0

Second, when the user clicks "No" on the MessageBox, I want to revert the value of the selected combo box item to what it was originally.

Why don't use use a variable to save the current value, and retrieve it back when required ?

    int My_ComboBox_Previous_SelectedIndex = -1;
    private void My_ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (My_ComboBox.SelectedIndex == My_ComboBox_Previous_SelectedIndex)
        {
            return;
        }
        if (MessageBox.Show("Are You Sure", "Confirm ?", MessageBoxButton.YesNo) != MessageBoxResult.Yes)
        {
            My_ComboBox.SelectedIndex = My_ComboBox_Previous_SelectedIndex;
            return;
        }
        else
        {
            My_ComboBox_Previous_SelectedIndex = My_ComboBox.SelectedIndex;
        }
    }
0

If I understood correctly what you want to implement:

    public partial class MainWindow : Window
    {
        public IReadOnlyList<string> SourceList { get; }
            = Array.AsReadOnly(new string[] { "PROD", "CERT", "DEV" });
        public MainWindow()
        {
            InitializeComponent();
        }

        private object oldSelectedItem = null;

        private const string message = "Are you sure you want to change environment to {0}?\nAll unsaved work will be lost!";
        private const string caption = "Change Environment?";
        private void EnvironmentComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var selector = (Selector)sender;
            if (oldSelectedItem is null)
            {
                oldSelectedItem = selector.SelectedItem;
                return;
            }
            if (oldSelectedItem == selector.SelectedItem)
            {
                return;
            }

            string env = (string)selector.SelectedItem;
            MessageBoxResult userResponse = MessageBox.Show(string.Format(message, env), caption,
                 MessageBoxButton.YesNo, MessageBoxImage.Warning);

            if (userResponse == MessageBoxResult.Yes)
            {
                bool envChange = ConfigurationService.SetEnvironmentValues(env);
                EnvironmentChangedMessage(envChange);

                oldSelectedItem = selector.SelectedItem;
            }
            else
            {
                selector.SelectedItem = oldSelectedItem;
            }
        }
    <ComboBox SelectedIndex="0">
        <FrameworkElement.Resources>
            <CollectionViewSource x:Key="sourceList"
                                    Source="{Binding SourceList}"/>
        </FrameworkElement.Resources>
        <ItemsControl.ItemsSource>
            <CompositeCollection>
                <ComboBoxItem Visibility="Collapsed">
                    - Select Environment -
                </ComboBoxItem>
                <CollectionContainer Collection="{Binding Source={StaticResource sourceList}}"/>
            </CompositeCollection>
        </ItemsControl.ItemsSource>
    </ComboBox>
EldHasp
  • 6,079
  • 2
  • 9
  • 24
  • I'm marking this one as the solution as it's pretty similar to what we ended up doing. I had to speak with a more senior developer who understands MVVM far better than me, and the solution was similar to this but in the VM class the developer had. Thank you for this input! – JD136 Dec 21 '22 at 20:42