AvalonDock document binding - c#

I'm using AvalonDock (link) to create my application. I have a toolbar and a documentpane (VisualStudio like) and each new document contains a textbox. And now I'd like to add an Undo button to my toolbar which will undo changes on the textbox wich is placed on the selected document.It's completely same like it's in Visual Studio.
What I'd like to accomplish is answered here but with TabControl and Tabs.
MyCode:
<Window x:Class="_app.MainWindow"
xmlns:my="clr-namespace:_app"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ad="clr-namespace:AvalonDock;assembly=AvalonDock"
xmlns:osc="clr-namespace:OpenSourceControls;assembly=DockPanelSplitter"
Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="24"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="24"/>
</Grid.RowDefinitions>
<!--...Menu And Toolbars -->
<ToolBarPanel Grid.Row="1" Width="Auto" HorizontalAlignment="Stretch" >
<ToolBar>
<Button Command="Undo">Undo</Button>
</ToolBar>
</ToolBarPanel>
<ad:DockingManager x:Name="dockManager" Grid.Row="2">
<ad:ResizingPanel Orientation="Vertical">
<ad:ResizingPanel Orientation="Horizontal">
<ad:DockablePane ad:ResizingPanel.ResizeWidth="150">
<ad:DockableContent x:Name="inputContent" Title="Workspace">
<!-- some dockable windows -->
</ad:DockableContent>
</ad:DockablePane>
<!-- here are added the new Documents-->
<ad:DocumentPane Name="mainDocPane" ItemsSource="{Binding ..Don't know..}">
<ad:DocumentPane.ItemContainerStyle>
<Style TargetType="ad:DocumentContent">
<Setter Property="Content" Value="{Binding Content}"/>
</Style>
</ad:DocumentPane.ItemContainerStyle>
</ad:DocumentPane>
</ad:ResizingPanel>
</ad:ResizingPanel>
</ad:DockingManager>
</Grid>
I create new document windows like this:
private void NewDocument_Click(object sender, RoutedEventArgs e)
{
string title = "Document" + (dockManager.Documents.Count+1).ToString();
var doc = new Document() { Title = title };
doc.Show(dockManager);
doc.Activate();
}
And the document class looks like this:
public partial class Document : AvalonDock.DocumentContent
{
public Document()
{
InitializeComponent();
}
}
XAML:
<ad:DocumentContent x:Class="_ap.Document"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:osc="clr-namespace:OpenSourceControls;assembly=DockPanelSplitter"
xmlns:ad="clr-namespace:AvalonDock;assembly=AvalonDock">
<DockPanel>
<TextBox Name="input" AcceptsReturn="True" />
</DockPanel>
So I'd like to apply the same mechanism from the link above on this code.
Thanks for any help.

See the ApplicaionCommands.Undo
Once you tie your Undo button to the in place command which comes with the .NET FW, when the TextBox has focus the undo will take place without you having to do anything.

Related

Handle the controls inside WPF User Control using WPF UI Automation

I am trying to handle a user control through WPF UI Automation,
I am unable to traverse through the User Control. Only able to traverse through the window where User Control is being consumed. Please suggest how can I work and get the handle of WPF user controls elements.
I am trying to handle through a windows application, I am following below code but it always returns null,
AutomationElement rootElement = AutomationElement.RootElement;
if (rootElement != null)
{
AutomationElement expander = appElement.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, "Expander Name"));
AutomationElement expander = appElement.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.AutomationIDProperty, "expID"));
}
The Expander in the user is written below,
<UserControl x:Class="UCCustomerInfo.CustInfo"
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"
xmlns:my2="clr-namespace:MyDatePicker;assembly=MyDatePicker"
mc:Ignorable="d"
Height="Auto"
xmlns:my="clr-namespace:UCCustomerInfo" Loaded="UserControl_Loaded">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/BFETH-CustomerMT;component/Resource/Resource-LinearGradientBrush.xaml"/>
<ResourceDictionary Source="pack://application:,,,/BFETH-CustomerMT;component/Resource/Resource-Control.xaml" />
<ResourceDictionary Source="pack://application:,,,/BFETH-CustomerMT;component/Resource/SBFEResources.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Expander Style="{x:Null}" FontSize="16" Header="By num" Height="Auto" Name="byNum" VerticalAlignment="Top"
Margin="3,10,0,0" FontWeight="Bold" Foreground="#4E87D4" IsExpanded="False" >
<Border Name="borderRMno" Margin="20,0,13,0" BorderThickness="2,2,2,2" CornerRadius="3"
BorderBrush="#ADD8E6" Background="#DFEFF0">
<Grid Name="GridRMLPbyRMNo" Grid.Row="2" Margin="0,5,0,5">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10"/>
<ColumnDefinition Width="140"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Label Name="Custo_No" Content="Cust No" Margin="0,4"
Grid.Column="1" Grid.Row="0" HorizontalAlignment="Left"/>
<TextBox Name="Cust_Search" Width="120" Height="26"
MaxLength="14"
Grid.Column="2" Grid.Row="0" Margin="0,3" HorizontalAlignment="left"
TabIndex="11"
/>
</Grid>
</Border>
</Expander>

Best way to go about switching views using MVVM

I'm working on a game where I am using a UI framework which works with XAML and MVVM. I have managed to get my framework hooked up and I am able to switch between views. Right now I am using data-templates along with the ContentControl to switch views, I am also using a state-like pattern to switch and I was wondering if this is a good approach to use? I am having a small problem with my views, the way I have things set up currenly I have my MainWindow.xaml which contains a data-template to my other xaml files. The problem is the views just get added to the MainWindow.xaml and I'm wondering if there is a way to hide the previous view/content so it looks as if I'm switching between windows/views rather than just adding to them. Here is a screenshot to illustrate what I currently have.Image of project. My xaml files are very simple and just contain a button for now, here are my xaml files:
`
MainWindow.xaml
<Grid
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:local="clr-namespace:PsalmsOfEia"
xmlns:viewmodels="clr-namespace:PsalmsOfEia.UI.Menus.ViewModels"
xmlns:views="clr-namespace:PsalmsOfEia.UI.Menus.Views">
<Grid.DataContext>
<viewmodels:MainViewModel />
</Grid.DataContext>
<Grid.Resources>
<DataTemplate DataType="{x:Type viewmodels:LoginViewModel}">
<views:LoginView/>
</DataTemplate>
</Grid.Resources>
<DockPanel LastChildFill="True">
<StackPanel>
<ContentControl Content="{Binding SelectedViewModel}"/>
<Button Content="Login" Command="{Binding ChangeCommand}"/>
</DockPanel>
</Grid>
LoginView.xaml
<UserControl x:Class="PsalmsOfEia.UI.Menus.Views.LoginView"
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"
xmlns:local="clr-namespace:PsalmsOfEia"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
xmlns:viewmodels="clr-namespace:PsalmsOfEia.UI.Menus.ViewModels"
xmlns:views="clr-namespace:PsalmsOfEia.UI.Menus.Views">
<UserControl.DataContext>
<viewmodels:LoginViewModel />
</UserControl.DataContext>
<UserControl.Resources>
<DataTemplate DataType="{x:Type viewmodels:CreateCharacterViewModel}">
<views:CreateCharacterView/>
</DataTemplate>
</UserControl.Resources>
<StackPanel>
<ContentControl Content="{Binding SelectedViewModel}"/>
<Button Content="Click Here" Command="{Binding LoginCommand}"/>
</StackPanel>
</UserControl>
`
Could anyone tell me if there is a better way of switching views as well as how to hide the content of the previous views (since at the moment everything is being added to the main window).
Thanks
-Joshmond
Not really sure what you're looking for but I use a TabControl
<TabControl>
<TabItem Header="Tab1">
<local:UserControl1/>
</TabItem>
<TabItem Header="Tab2">
<local:UserControl2/>
</TabItem>
<TabItem Header="Tab3">
<local:UserControl3/>
</TabItem>
</TabControl>
I try to minimise the amount of XAML in one file, so I create a UserControl and add them into the main view.
Im using stackpanel and usercontrol.
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel x:Name="myStackpanel1" Grid.Row="0" />
<StackPanel x:Name="myStackpanel2" Grid.Row="1" />
<Button x:Name="myButton" Width="200" Height="30" Grid.Row="2" Click="myButton_Click" Content="Click Me SP1" />
<Button x:Name="myButton2" Width="200" Height="30" Grid.Row="3" Click="myButton2_Click" Content="Click Me2 SP2" />
</Grid>
Code
private int i,j = 0;
public MainWindow()
{
InitializeComponent();
}
private void myButton_Click(object sender, RoutedEventArgs e)
{
i++;
if (i % 2 == 0)
{
myStackpanel1.Children.Clear();
myStackpanel1.Children.Add(new UserControl1());
}
else
{
myStackpanel1.Children.Clear();
myStackpanel1.Children.Add(new UserControl2());
}
}
private void myButton2_Click(object sender, RoutedEventArgs e)
{
j++;
if (j % 2 == 0)
{
myStackpanel2.Children.Clear();
myStackpanel2.Children.Add(new UserControl2());
}
else
{
myStackpanel2.Children.Clear();
myStackpanel2.Children.Add(new UserControl1());
}
}

MinWidth, MaxWidth, MinHeight, MaxHeight don't have effect for <UserControl>

I'm learning to create WPF application with Caliburn Micro framework.
Following the tutorial on the homepage: Basic Configuration, I removed the default generated <Window> xaml, instead, I have <UserControl> xaml and bootstrap it via my AppBoostrapper.
Here is the MainView.xaml:
<UserControl x:Class="SmartRenamer.Views.MainView"
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"
d:DesignHeight="300" d:DesignWidth="300"
MinHeight="300"
MinWidth="300"
MaxHeight="500"
MaxWidth="1000">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Menu IsMainMenu="True" Grid.Row="0">
<MenuItem Header="_File">
<MenuItem Header="_Open Folder..." x:Name="OpenFolder"></MenuItem>
</MenuItem>
<MenuItem Header="_About" />
</Menu>
<ScrollViewer HorizontalScrollBarVisibility="Visible" Grid.Row="1" MaxHeight="500" MaxWidth="1000">
<StackPanel>
<DataGrid x:Name="FilesList">
</DataGrid>
</StackPanel>
</ScrollViewer>
</Grid>
</UserControl>
The problem is I want to set the MinWidth, MaxWidth, MinHeight, MaxHeight for my application, but it seems that those configuration in the MainWindow.xaml isn't working.
Here is the two screenshots, where the window is still can be re-sized out of the defined range:
What am I wrong here?
The width and height properties of an UserControl is set by the container that holds that control. I.e. the DesignWidth and DesignHeigth that are used in the design-time are set in the UserControl but in runtime it uses the values set by the container.
I am not experienced in Caliburn Micro but it seems like you can define the design properties in the bootstrapper:
var settings = new Dictionary<string, object>
{
{ "Height" , 300},
{ "Width" , 300},
};
DisplayRootViewFor<ViewModel>(settings);

Dynamically reducing FontSize to avoid overflow

I have written a toy WPF application with a Button and an ItemsControl. Each time you click the Button, the string "AnotherWord" gets added to the ItemsControl. Now, the ItemsControl is displayed as horizontally oriented StackPanel with a fixed width (500 pixels). This means that when you click the button a certain number of times (actually six times), the newly added string gets clipped, like this:
"AnotherWord AnotherWord AnotherWord AnotherWord AnotherWord AnotherWo"
This happens when the FontSize is 13; if you lower it to 12.7 then there's room for the sixth occurence of "AnotherWord". My question is: Is there a way to make this adjustment at runtime so that you avoid the overflow?
EDIT:
In the context of the question, the fixed width of the StackPanel is obligatory - we cannot use more than the 500 pixels we have. Another requirement that the font must never become bigger than 13.
Here is all the code I wrote:
<!-- MainWindow.xaml -->
<Window x:Class="FontSize.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"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Window.Resources>
<DataTemplate x:Key="labelTemplate">
<Label FontSize="13" Content="AnotherWord"></Label>
</DataTemplate>
<ItemsPanelTemplate x:Key="panelTemplate">
<StackPanel Orientation="Horizontal" Width="500" Height="50" />
</ItemsPanelTemplate>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ItemsControl Grid.Row="0" ItemsSource="{Binding Path=MyStrings}" ItemTemplate="{StaticResource labelTemplate}"
ItemsPanel="{StaticResource panelTemplate}" />
<Button Grid.Row="1" Click="Button_Click"></Button>
</Grid>
</Window>
// MainWindow.xaml.cs
using System.Collections.ObjectModel;
using System.Windows;
namespace FontSize
{
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
MyStrings = new ObservableCollection<string>();
}
public ObservableCollection<string> MyStrings
{
get { return (ObservableCollection<string>) GetValue(MyStringsProperty); }
set { SetValue(MyStringsProperty, value); }
}
private static readonly DependencyProperty MyStringsProperty =
DependencyProperty.Register("MyStrings", typeof (ObservableCollection<string>), typeof (Window));
private void Button_Click(object sender, RoutedEventArgs e)
{
MyStrings.Add("AnotherWord");
}
}
}
Put your ItemsControl in a Viewbox and play with the following properties:
MaxWidth
MaxHeight
Stretch
StretchDirection
Edit
And remove the Width & Height property of your StackPanel.
Edit 2
Try something like that:
<!-- MainWindow.xaml -->
<Window x:Class="FontSize.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"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Window.Resources>
<DataTemplate x:Key="labelTemplate">
<Label FontSize="13" Content="AnotherWord"></Label>
</DataTemplate>
<ItemsPanelTemplate x:Key="panelTemplate">
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Viewbox Grid.Row="0" MaxWidth="500" Stretch="Uniform">
<ItemsControl
ItemsSource="{Binding Path=MyStrings}"
ItemTemplate="{StaticResource labelTemplate}"
ItemsPanel="{StaticResource panelTemplate}" />
</Viewbox>
<Button Grid.Row="1" Click="Button_Click"></Button>
</Grid>
</Window>
Edit 3
Change the horizontal alignment of the Viewbox so it isn't stretched to fill the grid. I've put "Center", replace by whatever you want.
...
<Viewbox
HorizontalAlignment="Center"
StretchDirection="DownOnly"
Grid.Row="0"
MaxWidth="500"
Stretch="Uniform">
...

Replace contents WPF grid control by grid in other XAML file

I'm trying to replace the content of a WPF grid control by another WPF grid defined in a second XAML file in code (c#).
(simplified example)
Window1.xaml:
<Window x:Class="Demo1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="_Set Grid" Click="MenuItem_Click" />
</Menu>
<StatusBar DockPanel.Dock="Bottom">
<StatusBarItem Name="statusItem">Status</StatusBarItem>
</StatusBar>
<Grid Name="header" DockPanel.Dock="Top">
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Name="txtHi" Grid.Row="0" Grid.Column="0">Hi</TextBlock>
<TextBlock Name="txtName" Grid.Row="0" Grid.Column="1">X</TextBlock>
</Grid>
<Grid Name="gridContent">
</Grid>
</DockPanel>
Windows2.xaml contains the grid that replaces gridContent
<Window x:Class="Demo1.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window2" Height="300" Width="300">
<Grid Name="grid2">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Label Grid.Column="1" Grid.Row="1">Hello !!!</Label>
</Grid>
The MenuItem_Click event in the code behind Windows1.xaml.cs contains:
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
Window2 win2 = new Window2();
gridContent = win2.grid2;
setStatus();
}
private void setStatus() {
statusItem.Content = "gridContent has " + gridContent.RowDefinitions.Count + " rows and " + gridContent.ColumnDefinitions.Count + " columns.";
}
Although the statusItem say the gridContent contains 2 rows and 2 columns after a click on the menu, the window is not changed and does not contain the text Hello!!!
Any ideas what I'm doing wrong?
If there are better solutions to "embed" a grid from a second xaml file, please let me know.
Thanks,
Robbie
Replacing the value of the gridContent variable cannot have an effect on the controls tree.
You must first disconnect the grid2 from its parent and then add it to the children of gridContent, like this:
win2.Content = null;
gridContent.Children.Add(win2.grid2);
This works (I tried), but it is not the recommended way to create a Window, extract its content then place it in another window. You should use a UserControl in place of Window2 and then you can put it directly inside gridContent.

Categories