I have a really simple WPF UserControl:
<UserControl x:Class="dr.SitecoreCompare.WPF.ConnectionEntry"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="connEntry"
BorderBrush="Navy" BorderThickness="1" Margin="5,0,0,5" >
<StackPanel Margin="0,10,0,0" >
<Label FontWeight="ExtraBold" Content="{Binding ElementName=connEntry, Path=Title}"></Label>
<Label Margin="0,5,0,0">Server:</Label>
<TextBox x:Name="txtServer" TabIndex="1" Text="{Binding Path=ServerName}" ></TextBox>
<Label>Database:</Label>
<TextBox x:Name="txtDatabase" TabIndex="2" Text="{Binding Path=DatabaseName}"></TextBox>
</StackPanel>
This is used twice in the same window. Now, I can select the first TextBox on both th instances of my UserControl, but the second ("txtDatabase") textbox cannot be selected, neither by tabbing or clicking. Why is this ? Am I missing something with regards to creating WPF usercontrols ?
EDIT:
DatabaseName is not readonly, it is a simple property. The XAML for the window the usercontrol is placed on looks like this:
<Window x:Class="dr.SitecoreCompare.WPF.ProjectDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:dr.SitecoreCompare.WPF"
Title="Choose project" Height="280" Width="500"
WindowStartupLocation="CenterOwner" WindowStyle="SingleBorderWindow" HorizontalAlignment="Center" ShowInTaskbar="False" ShowActivated="True" ResizeMode="NoResize" VerticalContentAlignment="Top" VerticalAlignment="Center">
<StackPanel>
<Label>Choose databases</Label>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<c:ConnectionEntry Grid.Column="0" x:Name="connMaster" Title="Master:" Padding="5" />
<c:ConnectionEntry Grid.Column="1" x:Name="connSlave" Title="Slave:" Padding="5" />
</Grid>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,0" >
<Button x:Name="btnCancel" Click="btnCancel_Click">Cancel</Button>
<Button x:Name="btnOK" Click="btnOK_Click">OK</Button>
</StackPanel>
</StackPanel>
</Window>
Try Mode=TwoWay in your binding. I've seen this where the initialization sets the value and the control can not set the the value.
<TextBox x:Name="txtDatabase" TabIndex="2" Text="{Binding Path=DatabaseName, Mode=TwoWay}"></TextBox>
This works in XamlPad, so I think there is something outside the code you posted that is causing the problem. Is DatabaseName readonly?
Related
I've created UserControl for adding/removing attributes using the buttons. It has ItemsControl with ObservableCollection of attributes bound to it as a ViewModel and button for adding new attribute to collection. Each new attribute creates an entity in collection which is also a UserControl with bound attribute ViewModel and button for deleting itself.
I wanted to write this functionality so the single attribute control (and other controls) can be reusable - and I use it in a few places. Currently adding new attributes works properly, but I can't find any working way for delete button to work properly and remove object from the collection.
I tried to refer through this.Parent, but CustomAttributeControl's parent is null, I tried to refer through Tag or use Prism.Core, but I couldn't implement anything properly for this to work and I couldn't find anyone with similar nested controls problem to base on. It's easy when there is no nested control for single attribute, but here I can't come up with anything. I'm fairly new to WPF and I feel there should be an easy way to do this.
single attribute control
attribute control's XAML:
<UserControl x:Class="xxx.UI.CustomAttributeControl"
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:models="clr-namespace:xxx.ViewModels.Attributes"
mc:Ignorable="d" >
<DockPanel Width="auto" HorizontalAlignment="Stretch" Margin="0,2">
<TextBox Text="{Binding Name}" Height="20" TextWrapping="Wrap" Width="160"/>
<TextBlock Width="60"/>
<ComboBox x:Name="DataType" Height="20" Width="120" SelectionChanged="DataType_SelectionChanged"/>
<TextBlock Width="10"/>
<TextBox Text="{Binding ListValues}" x:Name="ListValues" Height="20" TextWrapping="Wrap" Width="120"/>
<DockPanel HorizontalAlignment="Right">
<CheckBox IsChecked="{Binding Visible}" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="20,0"/>
<Button x:Name="Delete" Content="X" Width="22" Height="20" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="20,0"/>
</DockPanel>
</DockPanel>
</UserControl>
list control
list control's XAML:
<UserControl x:Class="xxx.UI.CustomAttributesControl"
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:xxx.UI"
mc:Ignorable="d">
<StackPanel>
<Label FontSize="20">Custom attributes</Label>
<StackPanel>
<DockPanel HorizontalAlignment="Stretch">
<Label Width="160" HorizontalAlignment="Left" HorizontalContentAlignment="Center">Attribute name</Label>
<TextBlock Width="60"/>
<Label Width="120" HorizontalAlignment="Left" HorizontalContentAlignment="Center">Attribute type</Label>
<TextBlock Width="10"/>
<Label Width="120" HorizontalAlignment="Left" HorizontalContentAlignment="Center">List values</Label>
<DockPanel HorizontalAlignment="Right">
<Label Width="60" HorizontalAlignment="Right" HorizontalContentAlignment="Center">Visible</Label>
<Label Width="60" HorizontalAlignment="Right" HorizontalContentAlignment="Center">Delete</Label>
</DockPanel>
</DockPanel>
<ItemsControl ItemsSource="{Binding}"> <!-- it's binding ObservableCollection of custom attributes from parent control -->
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:CustomAttributeControl />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<DockPanel HorizontalAlignment="Right">
<Button Margin="20,10" Click="AddAttribute">+ Add attribute</Button>
</DockPanel>
</StackPanel>
</StackPanel>
</UserControl>
Code for adding attribute in .xaml.cs:
private void AddAttribute(object sender, RoutedEventArgs e)
{
var attributes = (ObservableCollection<CustomAttribute>)DataContext;
attributes.Add(new CustomAttribute());
}
<Window
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" x:Class="WpfApplication1.MainWindow"
Title="MainWindow" Height="350" Width="550" MinHeight="350">
<DockPanel Background="BlanchedAlmond">
<DataGrid Background="YellowGreen" DockPanel.Dock="Top" MinHeight="100">
</DataGrid>
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" FlowDirection="RightToLeft" Margin="10" Background="YellowGreen">
<Button HorizontalAlignment="Right" Click="Button1Add_Click" Margin="5,0">Add text 1</Button>
<Button HorizontalAlignment="Right" Click="Button2Add_Click">Add text 2</Button>
<Button HorizontalAlignment="Right" Click="Button1_Click" Margin="5,0">Toggle textbox 1</Button>
<Button HorizontalAlignment="Right" Click="Button2_Click">Toggle textbox 2</Button>
</StackPanel>
<Grid Background="Red">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBox x:Name="TextBox1" Grid.Row="0" Background="AliceBlue" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">Test 1</TextBox>
<TextBox x:Name="TextBox2" Grid.Row="1" Background="AliceBlue" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">Test 2</TextBox>
</Grid>
</DockPanel>
</Window>
In the example above I am trying to achieve that the two textboxes in the middle just fill the available space between the top datagrid and the bottom stackpanel with buttons.
They have to divide that space between them depending on their text-content and their visibility.
Both properties can change by databindings, I simulated that with the click events.
But when the space is filled up they have to show a vertical scrollbar when needed.
The code sample above is not good. When I add text to a textbox, the grid-row becomes larger but disappears from the visible region, no scroll bar.
EDIT: I ended up with:
<ScrollViewer Background="AliceBlue" VerticalScrollBarVisibility="Auto">
<StackPanel Orientation="Vertical">
<Label x:Name="Label1" Margin="0,6,0,0">Test 1:</Label>
<TextBox x:Name="TextBox1" Padding="0,6"></TextBox>
<Label x:Name="Label2" Margin="0,6,0,0">Test 2:</Label>
<TextBox x:Name="TextBox2" Padding="0,6" ></TextBox>
</StackPanel>
</ScrollViewer>
You need to add a ScrollViewer in your XAML around the content.
ScrollViewer on MSDN
<ScrollViewer>
Content
</ScrollViewer>
In a WPF project, I want to dock a DataGrid to the bottom of a window so that if the window resizes, I will be able to utilize more of the DataGrid. Like this:
How do I do that? All my DockPanel attempts have failed.
The current attempt is here:
<Window x:Class="Foo.SQLDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:Foo.Controls"
Title="test" ResizeMode="CanResize" Width="400" Height="400">
<StackPanel Orientation="Vertical" Height="Auto" Width="Auto">
<StackPanel Orientation="Vertical">
<Label Content="SQL" HorizontalAlignment="Left"/>
<TextBox Width="377" Height="100" Name="txtSQL"/>
<Button Content="Run SQL" Click="Button_Click_1" />
</StackPanel>
<Label Content="Result" HorizontalAlignment="Left"/>
<ScrollViewer Width="Auto" Height="180" DockPanel.Dock="Right,Bottom"
ScrollViewer.CanContentScroll="True"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollBarVisibility="Auto">
<DataGrid x:Name="dataResult" />
</ScrollViewer>
</StackPanel>
</Window>
The height of the scrollviewer+datagrid will not adapt however.
First of all, using DockPanel.Dock without having a DockPanel as a parent doesn't do much...
In my example I changed your root StackPanel to a DockPanel so it will work as you want.
I also used DockPanel.LastChildFill property which makes sure the last child of the DockPanel will get all the remaining space:
<DockPanel LastChildFill="True">
<StackPanel Orientation="Vertical" DockPanel.Dock="Top">
<Label Content="SQL" HorizontalAlignment="Left"/>
<TextBox Width="377" Height="100" Name="txtSQL"/>
<Button Content="Run SQL" Click="Button_Click_1" />
</StackPanel>
<Label Content="Result" HorizontalAlignment="Left" DockPanel.Dock="Top"/>
<ScrollViewer DockPanel.Dock="Bottom,Right"
ScrollViewer.CanContentScroll="True"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollBarVisibility="Auto">
<DataGrid x:Name="dataResult" />
</ScrollViewer>
</DockPanel>
Finally, to make it really stretch on all the remaining space, I removed the Height property you set, as this blocked it from stretching.
Not sure if useful or if i understand you question the right way but have you tried this:
<DataGrid DockPanel.Dock="Right, Bottom" VerticalAlignment="Bottom" HorizontalAlignment="Right" ></DataGrid>
I have a WPF UserControl with a textbox. Here's how the textbox and it's parent control are defined:
<DockPanel Margin="10,20,10,10" FocusManager.FocusedElement="{Binding ElementName=uxJobNumber}" >
<TextBox x:Name="uxJobNumber" Text="{Binding JobNumber, Mode=TwoWay, ValidatesOnDataErrors=True}" TextWrapping="Wrap" FontSize="48" BorderBrush="Black" BorderThickness="1" Margin="10"/>
</DockPanel>
With the FocusManager.FocusedElement set, I can see a cursor bar present within the textbox. However, the cursor bar is not blinking, and does not allow the user to immediately start typing.
Without the FocusManager.FocusedElement set, when the application starts there is no cursor bar within the text box at all.
Here's the complete XAML
<UserControl x:Class=""
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:converters="clr-namespace:.Modules.Converters"
xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit/extended"
xmlns:extToolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit/extended"
mc:Ignorable="d">
<UserControl.Resources>
<converters:VisibilityConverter x:Key="Visibility" />
</UserControl.Resources>
<Canvas Width="1024" Height="768" >
<Border Style="{DynamicResource GroupBox}" Canvas.Left="36.261" Canvas.Top="32.131" Width="426.936">
<StackPanel>
<Border>
<TextBlock Text="STEP 1"/>
</Border>
<TextBlock Text="Enter the five (5) digit Job Number and click Verify." />
<Path/>
<DockPanel Margin="10,20,10,10" FocusManager.FocusedElement="{Binding ElementName=uxJobNumber}" >
<Button Content="Verify" Width="125" Height="65" HorizontalAlignment="Right" Command="{Binding SearchJobCommand}" Style="{DynamicResource RedButton}" Margin="0" DockPanel.Dock="Right" IsDefault="True"/>
<TextBox Text="{Binding JobNumber, Mode=TwoWay, ValidatesOnDataErrors=True}" TextWrapping="Wrap" FontSize="48" BorderBrush="Black" BorderThickness="1" x:Name="uxJobNumber" Margin="10" KeyboardNavigation.TabIndex="0" />
</DockPanel>
</StackPanel>
</Border>
<TextBlock Text="{Binding Error}" Visibility="{Binding HasError, Converter={StaticResource Visibility}}" Canvas.Left="48" Canvas.Top="288" FontSize="16" Width="403" Foreground="Red" />
</Canvas>
We finally resorted to using the Focus() method in the code behind when the form is done loading.
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
uxJobNumber.Focus();
}
Using your code I get this to work; blinking and all.
i have multiple items in my usercontrol. I put everything in a grid. But now i am trying, if the resolution of my screen changes, the window scales automatically. This just doesn't work.
I already used viewbox, but not with the wanted result.
This is my usercontrol:
<UserControl x:Class="NewWPFVragenBeheer.Maak_toets.Views.ChangeCourse"
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:converters="clr-namespace:NewWPFVragenBeheer.Converters"
mc:Ignorable="d" d:DesignHeight="200" d:DesignWidth="700"
>
<UserControl.Resources>
<XmlDataProvider x:Key="Vakken"
Source="C:\Users\Ruben\Desktop\Stage 26-04\stage_TFW\stage_TFW\NewWPFVragenBeheer\Data\Courses.xml"
XPath="/Courses/Course"
/>
<converters:RadioBoolToIntConverter x:Key="radioBoolToIntConverter" />
</UserControl.Resources>
<Viewbox Stretch="None">
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="722*" />
<ColumnDefinition Width="254*" />
</Grid.ColumnDefinitions>
<Label Content="Maximale tijd:" Height="28" FontWeight="Bold" HorizontalAlignment="Left" Margin="12,28,0,0" Name="label1" VerticalAlignment="Top" Width="177" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="215,30,0,0" Text="{Binding Path=MaxTime}" VerticalAlignment="Top" Width="145" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="215,2,0,0" Text="{Binding Path=ExamName,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" Name="textBox1" VerticalAlignment="Top" Width="145" />
<Label FontWeight="Bold" Content="Punten:" Height="28" HorizontalAlignment="Left" Margin="386,0,0,0" Name="label2" VerticalAlignment="Top" />
<TextBox Height="23" Text="{Binding Path=Score,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" HorizontalAlignment="Left" Margin="567,2,0,0" Name="textBox2" VerticalAlignment="Top" Width="120" />
<Label Content="{Binding Path= FeedbackText, UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" Height="28" HorizontalAlignment="Right" Margin="0,153,527,0" Name="label3" VerticalAlignment="Top" Width="200" Foreground="#FFF50D0D" />
</Grid>
</Viewbox>
</UserControl>
this usercontrol is set in a window:
<Window x:Class="NewWPFVragenBeheer.MaakToetsDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:view="clr-namespace:NewWPFVragenBeheer.Views"
Title="MaakToetsDialog"
WindowStyle ="SingleBorderWindow"
WindowState ="Maximized"
WindowStartupLocation="CenterScreen"
>
<view:MaakToetsView />
</Window>
¨please someone help.
Set the Grid to a fixed Width and Height, and set ViewBox.Stretch to Uniform. That should do it.
The correct answer likely is more complicated than the solution you seek, but I'll try to keep it short.
To do what you want, in my experience your best bet is to use a Grid as your primary initial element and then situate your controls within that Grid (or other Grids inside of it) and wrap the individual controls in ViewBoxes. After that tie the UserControl SizeChanged event to a method that forces the height and width of the UserControl to maintain an appropriate ratio.
That's the best way I have found to handle it on my WPF UIs.