locked
How can we cancel SelectedItemChanged? RRS feed

  • Question

  •  

    Hi pros,

    Anybody know how could we cancel SelectedItemChanged event in TreeView/ListBox/ComboBox.

    Basically, I have a master navigation tree and a detail view of object, everytime user change to a new "node" in tree i want to ask if user want to save changes made in detail view. Since i didn;t know how to preview selection changed, I used PreviewMouseDown in treeView.

    Here is my code:

     

    treeView.SelectedItemChanged(....)

    {

    LoadDetailView();

    }

     

    treeView.PreviewMouseDown(sender, MouseButtonEventArgs e)

    {

    //ask user save changed?

    //if "cancel" then e.Handle = true;

    //else e.Handle = false;

    }

     

    this seems working but without messagebox, if I use messagebox to show then the event seem disposed even e.Handle is true or false.

     

    I saw a post before but still no solution yet.

     

    Thanks,

    Danny

    Wednesday, November 14, 2007 5:46 PM

Answers

  • Instead of cancelling the SelectedItemChanged event, I think you can achieve all the required logic within the SelectedItemChanged event handler, here is an oversimplified demo:

     

    Code Block

    <Window x:Class="AnswerHarness.Window1"
            xmlns="
    http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="
    http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:xmlstack="clr-namespace:System.Xml;assembly=System.Xml"
        Title="Window1" Height="300" Width="400">
      <Window.Resources>
        <x:Array Type="{x:Type Button}" x:Key="buttons">
          <Button x:Name="Button1" Visibility="Collapsed" Width="100" Height="40"/>
          <Button x:Name="Button2" Visibility="Visible" Width="100" Height="40"/>
          <Button x:Name="Button3" Visibility="Collapsed" Width="100" Height="40"/>
        </x:Array>
        <XmlDataProvider x:Key="tree" XPath="*">
          <x:XData>
            <Products xmlns="">
              <Product>
                <Name>Product 1</Name>
                <ProductID>355</ProductID>
                <CategoryID>16</CategoryID>
                <Description>description...</Description>
              </Product>
              <Product>
                <Name>Product 2</Name>
                <ProductID>400</ProductID>
                <CategoryID>20</CategoryID>
                <Description>second description...</Description>
              </Product>
              <Product>
                <Name>Product 3</Name>
                <ProductID>500</ProductID>
                <CategoryID>11</CategoryID>
                <Description>third description...</Description>
              </Product>
            </Products>
          </x:XData>
        </XmlDataProvider>

        <HierarchicalDataTemplate ItemsSource="{Binding XPath=child::*}" x:Key="template">
          <TextBlock Name="textBlock" Text="{Binding Path=Name, Mode=OneWay}"/>
        </HierarchicalDataTemplate>
      </Window.Resources>
      <DockPanel>
        <TreeView DockPanel.Dock="Left" Width="200"
          Name="treeView"
          ItemsSource="{Binding Source={StaticResource tree}}"
          ItemTemplate="{StaticResource template}"
          Tag="{Binding Path=SelectedValue, RelativeSource={RelativeSource Self}}"/>
        <TextBox Name="textBox"/>
      </DockPanel>
    </Window>

     

    namespace AnswerHarness
    {
        public partial class Window1 : Window
        {
            private Boolean isDirty = false;
            public Window1()
            {
                InitializeComponent();
                this.DataContext = this;
                textBox.TextChanged += delegate
                {
                    isDirty = true;
                };

                this.treeView.SelectedItemChanged += delegate
                {
                    if (isDirty)
                    {
                        MessageBoxResult result = MessageBox.Show(
                            "Do you want to save the change?",
                            "Save",
                            MessageBoxButton.YesNo);

                        if (result == MessageBoxResult.Yes)
                        {
                            //Save something here.
                            isDirty = false;
                        }
                    }
                    LoadData(treeView.SelectedItem);
                };
            }

            void LoadData(Object selectedItem)
            {
                textBox.Text = selectedItem.ToString();
                isDirty = false;
            }
        }
    }

     

     

    Hope this helps

     

    Edit: I've marked this reply as an answer. If this reply doesn't help you or other community members provide a better solution, you can unmark this reply.

    Friday, November 16, 2007 7:28 AM

All replies

  • Instead of cancelling the SelectedItemChanged event, I think you can achieve all the required logic within the SelectedItemChanged event handler, here is an oversimplified demo:

     

    Code Block

    <Window x:Class="AnswerHarness.Window1"
            xmlns="
    http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="
    http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:xmlstack="clr-namespace:System.Xml;assembly=System.Xml"
        Title="Window1" Height="300" Width="400">
      <Window.Resources>
        <x:Array Type="{x:Type Button}" x:Key="buttons">
          <Button x:Name="Button1" Visibility="Collapsed" Width="100" Height="40"/>
          <Button x:Name="Button2" Visibility="Visible" Width="100" Height="40"/>
          <Button x:Name="Button3" Visibility="Collapsed" Width="100" Height="40"/>
        </x:Array>
        <XmlDataProvider x:Key="tree" XPath="*">
          <x:XData>
            <Products xmlns="">
              <Product>
                <Name>Product 1</Name>
                <ProductID>355</ProductID>
                <CategoryID>16</CategoryID>
                <Description>description...</Description>
              </Product>
              <Product>
                <Name>Product 2</Name>
                <ProductID>400</ProductID>
                <CategoryID>20</CategoryID>
                <Description>second description...</Description>
              </Product>
              <Product>
                <Name>Product 3</Name>
                <ProductID>500</ProductID>
                <CategoryID>11</CategoryID>
                <Description>third description...</Description>
              </Product>
            </Products>
          </x:XData>
        </XmlDataProvider>

        <HierarchicalDataTemplate ItemsSource="{Binding XPath=child::*}" x:Key="template">
          <TextBlock Name="textBlock" Text="{Binding Path=Name, Mode=OneWay}"/>
        </HierarchicalDataTemplate>
      </Window.Resources>
      <DockPanel>
        <TreeView DockPanel.Dock="Left" Width="200"
          Name="treeView"
          ItemsSource="{Binding Source={StaticResource tree}}"
          ItemTemplate="{StaticResource template}"
          Tag="{Binding Path=SelectedValue, RelativeSource={RelativeSource Self}}"/>
        <TextBox Name="textBox"/>
      </DockPanel>
    </Window>

     

    namespace AnswerHarness
    {
        public partial class Window1 : Window
        {
            private Boolean isDirty = false;
            public Window1()
            {
                InitializeComponent();
                this.DataContext = this;
                textBox.TextChanged += delegate
                {
                    isDirty = true;
                };

                this.treeView.SelectedItemChanged += delegate
                {
                    if (isDirty)
                    {
                        MessageBoxResult result = MessageBox.Show(
                            "Do you want to save the change?",
                            "Save",
                            MessageBoxButton.YesNo);

                        if (result == MessageBoxResult.Yes)
                        {
                            //Save something here.
                            isDirty = false;
                        }
                    }
                    LoadData(treeView.SelectedItem);
                };
            }

            void LoadData(Object selectedItem)
            {
                textBox.Text = selectedItem.ToString();
                isDirty = false;
            }
        }
    }

     

     

    Hope this helps

     

    Edit: I've marked this reply as an answer. If this reply doesn't help you or other community members provide a better solution, you can unmark this reply.

    Friday, November 16, 2007 7:28 AM
  •  

    But the problem is this will not stop the selectedItem to be deselected, even if you are not loading the data for that item.
    Wednesday, November 28, 2007 8:08 AM
  • not really the answer as the selection is not canceled. How are you going to mark you're own answer as the answer any way?


    Antony Sebastian
    Monday, January 12, 2009 9:52 PM
  • Hi,

    I have the same issue.  When I show a MessageBox to get user confirmation for Ok & Cancel, the normal execution of other events when e.Handle = false is not happening. Is there a way to handle MessgaeBox result correctly?

    Tuesday, October 5, 2010 2:21 PM
  • The ideal solution would be for MS to give us a PreviewSelectedItemChanged event, but unfortunately they haven't done so (yet).  It is possible to simulate this behavior, but it would be messy. You'd need to handle PreviewMouseDown, PreviewKeyDown, etc and determine which item the user is attempting to select.  This could be accomplished by checking the OriginalSource in the event args, which would give you a ui control (label, textbox, image or something) belonging to the list item's visual tree, then walk up the visual tree to find out what list item the control belongs to.  Once you've determined that, mark the event as handled to prevent the normal selection change from taking place, then ask the user about saving changes and handle their answer. When that is complete, manually change the selection to the new item. Yuck.
    • Proposed as answer by matte303 Wednesday, October 6, 2010 6:18 PM
    Wednesday, October 6, 2010 6:17 PM