Scale usercontrol in wpf? - wpf

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.

Related

Collapsed Tab Item Prevents Control Select in WPF Designer

I'm using Visual Studio Pro 2019, and I came across an issue when using the tab control. I created a test project to test switching between collapsed tabs programmatically, but found that, when in the designer, I'm unable to select the control within the tab when the tabs are collapsed. I found this answer confirming that the tab being collapsed is the issue.
My question is whether there is a fix for this that isn't just turning the tabs to visible, as it shifts the item's grid location.
The alternate solution could be to manually alternate the visibility of overlapping grids, but tabs seem to be the more appropriate solution.
xaml:
<Window x:Class="MainWindow"
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"
xmlns:local="clr-namespace:delete3"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800" Background="#FF424242">
<Grid>
<TabControl Name="Tabs" HorizontalAlignment="Left" Height="255" Margin="122,51,0,0" VerticalAlignment="Top" Width="437">
<TabItem Name="First" Header="TabItem" Visibility="Collapsed">
<Grid Background="#FFE5E5E5">
<TextBox HorizontalAlignment="Left" Height="23" Margin="143,129,0,0" TextWrapping="Wrap" Text="1" VerticalAlignment="Top" Width="29"/>
</Grid>
</TabItem>
<TabItem Name="Second" Header="TabItem" Visibility="Collapsed">
<Grid Background="#FFE5E5E5">
<TextBox HorizontalAlignment="Left" Height="23" Margin="195,90,0,0" TextWrapping="Wrap" Text="2" VerticalAlignment="Top" Width="29"/>
</Grid>
</TabItem>
</TabControl>
<Button Content="1" HorizontalAlignment="Left" Margin="191,359,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
<Button Content="2" HorizontalAlignment="Left" Margin="484,379,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click_1"/>
</Grid>

How to remove element from collection at child control level

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());
}

WPF Ribbon steals TAB

I have a simple WPF application with Ribbon and few controls. Unfortunately when pressing TAB key to change focus, Ribbon somehow manages looping only within itself, other controls don't get a chance...
This is the XAML:
<Window x:Class="WpfApplication4.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="http://schemas.microsoft.com/winfx/2006/xaml/presentation/ribbon"
Title="MainWindow" Height="350" Width="525" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="136" />
<RowDefinition Height="175*" />
</Grid.RowDefinitions>
<my:Ribbon HorizontalAlignment="Stretch" Name="ribbon1" VerticalAlignment="Top">
<my:RibbonTab Header="Ribbon">
<my:RibbonGroup>
<my:RibbonComboBox Label="ComboBox" Name="ribbonComboBox1">
<my:RibbonGallery MaxColumnCount="1">
<my:RibbonGalleryCategory>
<my:RibbonGalleryItem Content="An item" />
</my:RibbonGalleryCategory>
</my:RibbonGallery>
</my:RibbonComboBox>
</my:RibbonGroup>
</my:RibbonTab>
</my:Ribbon>
<TextBox TabIndex="1" Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="12,19,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" />
<TextBox TabIndex="2" Height="23" HorizontalAlignment="Left" Margin="12,48,0,0" Name="textBox2" VerticalAlignment="Top" Width="120" Grid.Row="1" />
OK. Let me answer myself. For my purposes it's OK to NOT to use TAB for Ribbon. For Ribbon I can use KeyTip(s), so basically I have just added Focusable="False" KeyboardNavigation.TabNavigation="None" into ribbon definition. So the whole code could look like this:
<Window x:Class="WpfApplication4.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="http://schemas.microsoft.com/winfx/2006/xaml/presentation/ribbon"
Title="MainWindow" Height="350" Width="525" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="136" />
<RowDefinition Height="175*" />
</Grid.RowDefinitions>
<my:Ribbon Focusable="False" KeyboardNavigation.TabNavigation="None" HorizontalAlignment="Stretch" Name="ribbon1" VerticalAlignment="Top">
<my:RibbonTab Header="Ribbon" KeyTip="R">
<my:RibbonGroup>
<my:RibbonComboBox KeyTip="C" Label="ComboBox" Name="ribbonComboBox1">
<my:RibbonGallery MaxColumnCount="1">
<my:RibbonGalleryCategory>
<my:RibbonGalleryItem Content="An item" />
</my:RibbonGalleryCategory>
</my:RibbonGallery>
</my:RibbonComboBox>
</my:RibbonGroup>
</my:RibbonTab>
</my:Ribbon>
<TextBox TabIndex="1" Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="12,19,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" />
<TextBox TabIndex="2" Height="23" HorizontalAlignment="Left" Margin="12,48,0,0" Name="textBox2" VerticalAlignment="Top" Width="120" Grid.Row="1" />
</Grid>
</Window>
KeyboardNavigation.TabNavigation="Continue" does it for me, using System.Windows.Controls.Ribbon.dll

Prevent manual scrolling of a ScrollViewer

I have a ScrollViewer which wraps a bunch of dynamically created TextBox controls. The HorizontalScrollBarVisibility and VerticalScrollBarVisibility are both set to Hidden. I am programmatically scrolling the ScrollViewer in response to the user scrolling a gridview.
The problem i am having is that when the user places the focus on one of those TextBox elements and then presses the left/right arrow keys, the ScrollViewer is scrolling. I want to prevent this manual scrolling and only allow programmatic scrolling. Obviously disabling the ScrollViewer is not an option as the user needs to be able to add text to the TextBoxes inside it. Similarly, setting the HorizontalScrollBarVisibility property to Disabled doesn't work, as that resets the scroll offset back to zero.
How can i lock scrolling, or prevent manual scrolling?
By removing manual operation of the scroll bars, and hiding them, you are basically saying you want something that has a list of items, that can be scrolled from code, but is not a ListBox...
Conclusion: Don't use a ListBox :)
As you are managing the scrolling yourself, why not parent the TextBoxes under a StackPanel within a canvas (with a clipping rectangle of course). Then use the Canvas.Top/Left properties on the StackPanel to scroll it.
The example below does that. I added a slider bound to the Canvas.Top property so you can test it.
Xaml Example:
<UserControl x:Class="SilverlightApplication1.NotAListbox"
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"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<Canvas Background="Aquamarine" HorizontalAlignment="Center" Name="canvas1" VerticalAlignment="Center" Width="200" Height="200">
<Canvas.Clip>
<RectangleGeometry Rect="0,0,200,200"></RectangleGeometry>
</Canvas.Clip>
<StackPanel Canvas.Top="{Binding ElementName=slider1, Path=Value}" Name="stackPanel1">
<TextBox Height="23" Text="textBox 1" Width="120" />
<TextBox Height="23" Text="textBox 2" Width="120" />
<TextBox Height="23" Text="textBox 3" Width="120" />
<TextBox Height="23" Text="textBox 4" Width="120" />
<TextBox Height="23" Text="textBox 5" Width="120" />
<TextBox Height="23" Text="textBox 6" Width="120" />
<TextBox Height="23" Text="textBox 7" Width="120" />
<TextBox Height="23" Text="textBox 8" Width="120" />
<TextBox Height="23" Text="textBox 9" Width="120" />
</StackPanel>
</Canvas>
<Slider Height="171" HorizontalAlignment="Center" Margin="316,62,57,66" Name="slider1" VerticalAlignment="Center" Width="27" Orientation="Vertical" Minimum="-223" Maximum="200" />
</Grid>
</UserControl>

WPF UserControl - cannot select TextBox

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?

Resources