Why the trigger doesn't work after GridSplitter is dragged - wpf

Due to project privacy protection, I can't paste the product code here. So I made a simple example to show the problem.
I have a window like this:
When I click the Right button, I want the Right Column hide and the Left Column Stretch to full window:
Here is my Xaml:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="0"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition x:Name="rightCol" MinWidth="0"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0">
<Button Height="100" Content="Left" />
</StackPanel>
<GridSplitter Grid.Column="1" Width="10" VerticalAlignment="Stretch" HorizontalAlignment="Center"/>
<StackPanel x:Name="right" Grid.Column="2" >
<Button Height="100" Content="Right" Click="Button_Click" />
</StackPanel>
</Grid>
</Window>
And here is my code-behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
var b = new Binding("Visibility")
{
Source = this.right
};
var style = new Style(typeof(ColumnDefinition))
{
Setters =
{
new Setter(ColumnDefinition.WidthProperty, new GridLength(300)),
new Setter(ColumnDefinition.MinWidthProperty, 0.0),
}
};
style.Triggers.Add(new DataTrigger()
{
Binding = b,
Value = System.Windows.Visibility.Collapsed,
Setters =
{
new Setter(ColumnDefinition.WidthProperty, new GridLength(0)),
new Setter(ColumnDefinition.MaxWidthProperty, double.PositiveInfinity),
new Setter(ColumnDefinition.MinWidthProperty, 0.0),
}
});
this.rightCol.Style = style;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.right.Visibility = System.Windows.Visibility.Collapsed;
}
}
When I run it and Click the Right button, it works fine. But if I drag the GridSplitter before I Click the Right button, the trigger doesn't work:
Why this happened?
Note:
If I use below code, it can work.
private void Button_Click(object sender, RoutedEventArgs e)
{
this.right.Visibility = System.Windows.Visibility.Collapsed;
this.rightCol.Width = new GridLength(0);
}
But is there any way to use trigger?

I got my answer from this link:
GridSplitter overrides ColumnDefinition's style trigger?
So below code works fine:
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
var b = new Binding("Visibility")
{
Source = this.rightPane,
Mode = BindingMode.OneWay
};
var style = new Style(typeof(ColumnDefinition))
{
Setters =
{
new Setter(ColumnDefinition.WidthProperty, new GridLength(300)),
new Setter(ColumnDefinition.MinWidthProperty, 0.0),
}
};
/*
style.Triggers.Add(new DataTrigger()
{
Binding = b,
Value = System.Windows.Visibility.Collapsed,
Setters =
{
new Setter(ColumnDefinition.WidthProperty, new GridLength(0)),
new Setter(ColumnDefinition.MaxWidthProperty, double.PositiveInfinity),
new Setter(ColumnDefinition.MinWidthProperty, 0.0),
}
});*/
Storyboard sb = new Storyboard();
ObjectAnimationUsingKeyFrames oaf = new ObjectAnimationUsingKeyFrames();
DiscreteObjectKeyFrame disobj = new DiscreteObjectKeyFrame();
disobj.KeyTime = TimeSpan.FromMilliseconds(0);
disobj.Value = GridLength.Auto;
oaf.KeyFrames.Add(disobj);
sb.Children.Add(oaf);
Storyboard.SetTargetProperty(oaf, new PropertyPath(ColumnDefinition.WidthProperty));
var actionBegin = new BeginStoryboard();
actionBegin.Storyboard = sb;
actionBegin.Name="BeginStoryboard1";
var actionEnd = new RemoveStoryboard();
actionEnd.BeginStoryboardName = "BeginStoryboard1";
var trigger = new DataTrigger()
{
Binding = b,
Value = System.Windows.Visibility.Collapsed
};
trigger.EnterActions.Add(actionBegin);
trigger.ExitActions.Add(actionEnd);
style.Triggers.Add(trigger);
style.RegisterName(actionBegin.Name, actionBegin);
this.rightCol.Style = style;
}

Related

Custom WPF MessageBox does not return MessageBoxResult

This is the xaml "SidiMessageBoxWindow.xaml" file:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d">
<Border>
<Grid x:Name="mainGrid" Margin="0">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ScrollViewer Grid.Row="0" VerticalScrollBarVisibility="Auto" Margin="0">
<TextBlock x:Name="TextBlock" TextWrapping="Wrap" Text="TextBlock" ScrollViewer.VerticalScrollBarVisibility="Auto" Height="Auto"/>
</ScrollViewer>
<Grid Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Height="Auto" Width="Auto" Margin="0,10,0,0">
<Button x:Name="btnCancel" Content="Cancel" Width="Auto" MinWidth="0" Height="30"
HorizontalAlignment="Right" HorizontalContentAlignment="Center" VerticalAlignment="Center" VerticalContentAlignment="Center"
Margin="0,0,45,0" Padding="4,0,4,0" BorderThickness="1" />
<Button x:Name="btnOk" Content="Ok" Width="Auto" MinWidth="40" Height=" 30"
HorizontalAlignment="Right" HorizontalContentAlignment="Center" VerticalAlignment="Center" VerticalContentAlignment="Center"
Margin="0" Padding="4,0,4,0" BorderThickness="1" />
</Grid>
</Grid>
</Border>
and here the "SidiMessageBox1" class
I can't use "messageBox.ShowDialog();" here because I have to use the class "NTWindow" which I don't have access to.
public class SidiMessageBox1 : SidiMessageBoxWindow1
{
public static MessageBoxResult Show(ChartControl chartControl, string text, MessageBoxButton buttons = MessageBoxButton.OK)
{
if (chartControl == null)
{
return MessageBoxResult.None;
}
var messageBox = CreateMessageBox(chartControl, text, buttons);
messageBox.Show();
return messageBox.MsgBoxResult;
}
private static SidiMessageBoxWindow1 CreateMessageBox(ChartControl chartControl, string text, MessageBoxButton buttons)
{
return new SidiMessageBoxWindow1(text, buttons)
{
Owner = chartControl.OwnerChart,
Foreground = Application.Current.TryFindResource("FontControlBrush") as SolidColorBrush
};
}
}
and here is the SidiMessageBoxWindow1 class
public class SidiMessageBoxWindow1 : NTWindow
{
private static readonly string xamlFilePath = Path.Combine(Globals.UserDataDir, #"bin\Custom\AddOns\Sidi\SidiMessageBoxWindow.xaml");
private string text;
private Button btnOk, btnCancel;
private TextBlock textBlock;
private MessageBoxButton buttons;
public SidiMessageBoxWindow1()
{
}
public SidiMessageBoxWindow1(string text, MessageBoxButton buttons)
{
this.text = text;
Caption = "SidiMessageBox";
Topmost = true;
MinHeight = 100;
MinWidth = 200;
ResizeMode = ResizeMode.NoResize;
SizeToContent = SizeToContent.WidthAndHeight;
WindowStartupLocation = WindowStartupLocation.CenterOwner;
Content = LoadXaml(xamlFilePath);
Buttons = buttons;
}
private void OkButton_Click(object sender, RoutedEventArgs e)
{
btnOk.Click -= OkButton_Click;
Close();
}
private void CancelButton_Click(object sender, RoutedEventArgs e)
{
btnCancel.Click -= CancelButton_Click;
Close();
}
private DependencyObject LoadXaml(string xmlFilePath)
{
Window page;
FileStream fs = new FileStream(xmlFilePath, FileMode.Open);
page = (Window)XamlReader.Load(fs);
btnOk = LogicalTreeHelper.FindLogicalNode(page, "btnOk") as Button;
btnCancel = LogicalTreeHelper.FindLogicalNode(page, "btnCancel") as Button;
textBlock = LogicalTreeHelper.FindLogicalNode(page, "TextBlock") as TextBlock;
textBlock.Text = text;
return page.Content as DependencyObject;
}
public MessageBoxButton Buttons
{
get
{
return buttons;
}
set
{
buttons = value;
btnCancel.Visibility = Visibility.Collapsed;
btnOk.Visibility = Visibility.Collapsed;
switch (buttons)
{
case MessageBoxButton.OK:
btnOk.Visibility = Visibility.Visible;
btnOk.Click += OkButton_Click;
break;
case MessageBoxButton.OKCancel:
btnCancel.Visibility = Visibility.Visible;
btnOk.Visibility = Visibility.Visible;
btnOk.Click += OkButton_Click;
btnCancel.Click += CancelButton_Click;
break;
}
}
}
public MessageBoxResult MsgBoxResult { get; set; }
}
call:
var result = SidiMessageBox1.Show(ChartControl, "text");
the messageboxwindow looks like this:
everything works fine, as it should, except that I don't get a "MessageBoxResult" back. Unfortunately I don't know how to do that with this code.
I thank "BionicCode" for his explanation and hope for your understanding, because i am still quite a beginner ;-)
To use the Thread class is considered an obsolete programming model. Since the introduction of async and await with .NET Framework 4.5 the recommended programming model is the Microsoft Docs: Task asynchronous programming model.
As the member name Dispatcher.InvokeAsync suggests, this method is awaitable and supports asynchronous execution.
Your code actually does not execute the Window on a new thread. Because you use post related code to the Dispatcher, the Window is shown on the main thread.
Showing another Window will not block the other Window instances.
Additionally, your posted code is quite smelly. You should never block a constructor. But showing a modal dialog from a constructor will block construction. A constructor must initialize the members and return immediately.
Instead you must create and show the Window instance from your static Show method:
public static MessageBoxResult Show(ChartControl chartControl, string text, MessageBoxButton buttons)
{
if (chartControl == null)
{
return MessageBoxResult.None;
}
SidiMessageBoxWindow messageBox = CreateMessageBox(chartControl, text, buttons);
// If just an OK button, allow the user to just move away from the dialog
if (buttons == MessageBoxButton.OK)
{
messageBox.Show();
}
else
{
messageBox.ShowDialog();
}
return messageBox.MsgBoxResult;
}
private static SidiMessageBoxWindow CreateMessageBox(ChartControl chartControl, string text, MessageBoxButton buttons)
{
return new SidiMessageBoxWindow(xamlFilePath, logFilePath, text, buttons, chartControl)
{
Owner = chartControl.OwnerChart,
Foreground = Application.Current.TryFindResource("FontControlBrush") as SolidColorBrush
};
}
private SidiMessageBoxWindow(ChartControl chartControl, string text, MessageBoxButton buttons)
{
this.chartControl = chartControl;
this.text = text;
this.buttons = buttons;
}

Adding a Control per Mouse Click in Run Time

public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Grid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Button button1 = new Button();
Point tPosition = Mouse.GetPosition(this);
button1.Margin = new Thickness(tPosition.X,tPosition.Y,0,0) ;
button1.Width = 75;
this.AddChild(button1);
}
}
I think the code is pretty self-explanatory, I used a code that is approved in other thread here in stackoverflow, it doesn't give any error, but it also doesn't show up, do I need to refresh the window? And how?
by request, the XAML
<Window x:Class="Ampeldingensthingy.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid MouseLeftButtonDown="Grid_MouseLeftButtonDown" Name="hans">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="398*" />
<ColumnDefinition Width="105*" />
</Grid.ColumnDefinitions>
</Grid>
</Window>
Window can have only one children and I think you already have one that is Grid whose MouseButtonDown you subscribing. Give a name to that Grid and then replace
this.AddChild(button1);
with
grid.Children.Add(button1);
here grid is the name given to Grid.
The object "this" depicts the Window object here. Content of a ContentControl must be a single element. Hence append the Button that is "button1" inside a parent Grid. For example
private void Button_Click(object sender, RoutedEventArgs e)
{
Button button1 = new Button();
Point tPosition = Mouse.GetPosition(this);
button1.Margin = new Thickness(tPosition.X, tPosition.Y, 0, 0);
button1.Width = 75;
MainGrid.Children.Add(button1);
}
And in your Xaml
<Grid x:Name="MainGrid">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Button Click="Button_Click" Content="click" Grid.Row="1"/>
</Grid>
public partial class MainWindow : Window
{
public StackPanel SPanel{get;set;}
public MainWindow()
{
InitializeComponent();
SPanel = new StackPanel { Orientation = Orientation.Vertical };
}
private void Grid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Button button1 = new Button();
Point tPosition = Mouse.GetPosition(this);
button1.Margin = new Thickness(tPosition.X,tPosition.Y,0,0) ;
button1.Width = 75;
SPanel.Children.Add(button1);
window.Content = SPanel;
}
}
try to do the same with a canvas. the buttons will popup at the position you gave them.

Data Grid not updating from ViewModel

Do you know why looking at the code in the XAML and ViewModel why a Data Grid wont update when the an item is added? I know the DataGrid binding is correct as will add an item if I add it by code, however I am adding a item via a view.
Also the getter of the ObservableCollection is getting hit every time I do add a item.
Thanks
------ Code ------
XAML
<Window x:Class="Importer.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Product Group" Height="350" Width="721"
xmlns:VM="clr-namespace:Importer.ViewModels">
<Window.DataContext>
<VM:ProductsViewModel />
</Window.DataContext>
<Grid Margin="0,0,0.4,0.4">
<DataGrid x:Name="dgGrid" ColumnWidth="Auto" Margin="10,10,0,0" VerticalAlignment="Top"
ItemsSource="{Binding ProductCollection}" HorizontalAlignment="Left" AutoGenerateColumns="False" >
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}" Header="Name" Width="150"/>
<DataGridTextColumn Binding="{Binding Description}" Header="Description" Width="400" />
</DataGrid.Columns>
</DataGrid>
<Button x:Name="btnAddProjectGroup" Content="Add Project Group" HorizontalAlignment="Left" Margin="10,277,0,0" VerticalAlignment="Top" Width="135" Click="btnAddProjectGroup_Click"/>
</Grid>
</Window>
VIEW 1 (that uses the XAML above)
public partial class MainWindow : Window
{
ProductsViewModel m_VM = new ProductsViewModel();
public MainWindow()
{
InitializeComponent();
}
private void btnAddProjectGroup_Click(object sender, RoutedEventArgs e)
{
// Open new window here to add a new project group
AddProductGroup dlg = new AddProductGroup(m_VM);
dlg.ShowDialog();
}
}
VIEW 2 - The view that passes the values to add to the collection
public partial class AddProductGroup : Window
{
ProductGroupBindable newProduct = new ProductGroupBindable();
ProductsViewModel viewModel = null;
public AddProductGroup(ProductsViewModel vm)
{
viewModel = vm;
InitializeComponent();
}
private void btnOK_Click(object sender, RoutedEventArgs e)
{
newProduct.Id = System.Guid.NewGuid();
newProduct.Name = txtName.Text;
newProduct.Description = txtDescription.Text;
viewModel.AddProduct(newProduct);
this.Close();
}
}
VIEWMODEL
private ObservableCollection<ProductGroupBindable> m_ProductCollection;
public ProductsViewModel()
{
if (m_ProductCollection == null)
m_ProductCollection = new ObservableCollection<ProductGroupBindable>();
}
public ObservableCollection<ProductGroupBindable> ProductCollection
{
get
{
return m_ProductCollection;
}
set
{
m_ProductCollection = value;
}
}
private ObservableCollection<ProductGroupBindable> Test()
{
m_ProductCollection.Add(new ProductGroupBindable { Description = "etc", Name = "test12" });
m_ProductCollection.Add(new ProductGroupBindable { Description = "etc", Name = "test123" });
return ProductCollection;
}
public void AddProduct(ProductGroupBindable newProduct)
{
m_ProductCollection.Add(newProduct);
//NotifyPropertyChanged("ProductCollection");
}
You set DataContext in XAML:
<Window.DataContext>
<VM:ProductsViewModel />
</Window.DataContext>
and your dialog works on another instance of ProductsViewModel which you create in code:
ProductsViewModel m_VM = new ProductsViewModel();
Easiest workaround would be to pass DataContext to your AddProductGroup dialog:
AddProductGroup dlg = new AddProductGroup(this.DataContext as ProductsViewModel);
EDIT
or instead of setting DataContext in XAML do set it in code:
public MainWindow()
{
InitializeComponent();
this.DataContext = m_VM;
}

About setbinding in canvas

<StackPanel Height="650" Width="650" Background="Green" HorizontalAlignment="Center" VerticalAlignment="Center">
<ItemsControl Name="Display_Test" Margin="10">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Background="Black" Width="600" Height="600"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding}" Margin="15" Height="500" Width="500"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
// c# code start ====================================================================
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
this.InitializeComponent();
Canvas canvasSample = new Canvas();
canvasSample.Width = 100;
canvasSample.Height = 100;
canvasSample.Background = new SolidColorBrush(Colors.LightBlue);
CanvasList.Add(canvasSample);
Canvas canvasSample2 = new Canvas();
canvasSample2.Width = 100;
canvasSample2.Height = 100;
canvasSample2.Background = new SolidColorBrush(Colors.LightGreen);
CanvasList.Add(canvasSample2);
Rectangle rectangleSample = new Rectangle();
rectangleSample.Width = 30;
rectangleSample.Height = 30;
RectangleList.Add(rectangleSample);
Rectangle rectangleSample2 = new Rectangle();
rectangleSample2.Width = 30;
rectangleSample2.Height = 30;
RectangleList.Add(rectangleSample2);
Display_Test.ItemsSource = CanvasList;
this.MouseDoubleClick += new MouseButtonEventHandler(MainWindow_MouseDoubleClick);
}
void MainWindow_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
for (int nCanvasNum = 0; nCanvasNum < CanvasList.Count; nCanvasNum++)
{
Binding conBinding = new Binding()
{
Source = RectangleList
};
CanvasList[nCanvasNum].DataContext = RectangleList;
CanvasList[nCanvasNum].SetBinding(ItemsControl.ItemsSourceProperty, conBinding);
}
}
ObservableCollection<Canvas> _canvasList = new ObservableCollection<Canvas>();
public ObservableCollection<Canvas> CanvasList
{
get { return _canvasList; }
set
{
_canvasList = value;
OnPropertyChanged(new PropertyChangedEventArgs("CanvasList"));
}
}
ObservableCollection<Rectangle> _rectangleList = new ObservableCollection<Rectangle>();
public ObservableCollection<Rectangle> RectangleList
{
get { return _rectangleList; }
set
{
_rectangleList = value;
OnPropertyChanged(new PropertyChangedEventArgs("RegtangleList"));
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
{
PropertyChanged(this, e);
}
}
#endregion
}
// c# code end ====================================================================
when i clicked mousebutton double I want to create RectangleList in CanvasList...
But I'm afraid I can't show that...I think that is problem because of setbinding...
I will wait for your answer....
CanvasList[nCanvasNum].SetBinding(ItemsControl.ItemsSourceProperty, conBinding); won't work bevause Canvas is not derived from ItemsControl and does not have ItemSource property. It has children property but it is not dependency property so you can't bind to it but you can add childrens manually. You can try to use ItemsControl instead of Canvas and set Canvas as a panel for ItemsControl the same way you did it to Show canvases

How to create silverlight sequence animation programmatically?

I need to animate a rectangle to move horizontally first, then after 2 second make it move vertically. All this should be done programmatically.
Anybody can help me? Thanks!
Using the following XAML:
<UserControl x:Class="SilverlightApplication1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas x:Name="LayoutRoot">
<Rectangle x:Name="myBox" Fill="Red" Height="100" Width="100" Canvas.Left="0" Canvas.Top="0" />
</Canvas>
</UserControl>
You could create the animation programatically using this:
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
Loaded += MainPage_Loaded;
}
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
var moveAnimation = CreateAnimation(this.myBox);
moveAnimation.Begin();
}
public Storyboard CreateAnimation(FrameworkElement element)
{
var storyboard = new Storyboard();
var downAnimation = new DoubleAnimationUsingKeyFrames();
Storyboard.SetTarget(downAnimation, element);
Storyboard.SetTargetProperty(downAnimation, new PropertyPath(Canvas.TopProperty));
downAnimation.KeyFrames.Add(new EasingDoubleKeyFrame
{
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(2)),
Value = 200
});
storyboard.Children.Add(downAnimation);
var overAnimation = new DoubleAnimationUsingKeyFrames();
Storyboard.SetTarget(overAnimation, element);
Storyboard.SetTargetProperty(overAnimation, new PropertyPath(Canvas.LeftProperty));
overAnimation.KeyFrames.Add(new EasingDoubleKeyFrame
{
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(2)),
Value = 0
});
overAnimation.KeyFrames.Add(new EasingDoubleKeyFrame
{
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(4)),
Value = 200
});
storyboard.Children.Add(overAnimation);
return storyboard;
}
}

Resources