WPF Moving Element problem - c#

I am probably over-doing a very simple problem, but this is what I have a the moment:
I have several buttons and a listbox of items in which the user can select and interact with. My application also moves those elements in accordance to the application width/height, such as follows:
listBox1.Margin = new Thickness(this.ActualWidth * 0.84, this.ActualHeight * 0.3, 0, 0);
I am able to select the items within the listbox and click on buttons appropriately while in windowed mode, but as I begin to stretch the application larger, I try to click on the items, and I cannot do so.. is this because I also need to update their hit-detection rectangles as well? Or perhaps am I moving the items incorrectly? I am at a loss.. any information would be very helpful at this point...thanks!

Not sure why you can't click the items anymore after resizing. That can have a lot of reasons. Obviously you want to have proportional margins around the ListBox. You would normally do that with a Grid:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.83*"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="0.3*"/>
<RowDefinition/>
</Grid.RowDefinitions>
<ListBox x:Name="listBox1" Grid.Column="1" Grid.Row="1"/>
</Grid>

I write this XAML:
<Window x:Class="StackOverflow_MovingProblem.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.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ListBox Name="listbox1" ItemsSource="{Binding Path=list}" />
<StackPanel Grid.Row="1" Orientation="Horizontal">
<Button Content="button1" />
<Button Content="button2" />
<Button Content="button3" />
</StackPanel>
</Grid>
</Window>
with this code-behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
SizeChanged += new SizeChangedEventHandler(MainWindow_SizeChanged);
list = new ObservableCollection<string>();
list.Add("item1");
list.Add("item2");
list.Add("item3");
}
public ObservableCollection<string> list { get; set; }
void MainWindow_SizeChanged(object sender, SizeChangedEventArgs e)
{
listbox1.Margin = new Thickness(this.ActualWidth * 0.84,
this.ActualHeight * 0.3, 0, 0);
}
}
but I'm not able to reproduce your problem. Check my code if there is something different with your code and tell me what, so I can give you some advices. Thank you

Related

WinUI 3 ItemsRepeater re-orders/removes items when scrolling within a ScrollViewer and using UniformGridLayout

Wanted to post my issue I have with WinUI 3 in .NET 6 here too, maybe it's not a bug and I am doing something wrong.
First of all a link to the issue on Github: https://github.com/microsoft/microsoft-ui-xaml/issues/4516
A sample project can be found here: https://github.com/brechtb86/microsoft-ui-xaml-issues
Describe the bug
When using an ItemsRepeater in a ScrollViewer on a Page within a NavigationView with a custom user control in the ItemTemplate and you start to scroll up and down, the items are re-ordered or even removed. The items are just simple objects and a UserControl bound to some properties of that object.
Steps to reproduce the bug
Open the page "ItemsRepeater Scroll Issue (re-order/remove)". Items are ordered correctly.
Start scrolling up and down. Items are re-ordered and sometimes removed.
Switch to another page.
Switch back to page "ItemsRepeater Scroll Issue (re-order/remove)". Items are ordered correctly again.
Rinse and repeat.
Expected behavior
Items should stay in the same order.
I'm using the MVVM pattern, I'm using DI to manage my viewmodels with Ninject. The project is very simple:
ItemsRepeaterScrollIssuePage.xaml:
<Page
x:Class="WinUI3Issues.ItemsRepeaterScrollIssuePage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:WinUI3Issues"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:models="using:WinUI3Issues.Models"
xmlns:userControls="using:WinUI3Issues.UserControls"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
DataContext="{Binding Path=ItemsRepeaterScrollIssueViewModel, Source={StaticResource ViewModelLocator}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="Start scrolling" />
<ScrollViewer Grid.Row="1">
<ItemsRepeater ItemsSource="{Binding Path=DummyObjects}">
<ItemsRepeater.Layout>
<UniformGridLayout Orientation="Horizontal" ItemsStretch="Fill" MinColumnSpacing="24" MinRowSpacing="24"></UniformGridLayout>
</ItemsRepeater.Layout>
<ItemsRepeater.ItemTemplate>
<DataTemplate x:DataType="models:DummyObject">
<Grid>
<userControls:DummyObjectControl Title="{Binding Path=Name}"></userControls:DummyObjectControl>
</Grid>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</ScrollViewer>
</Grid>
</Page>
DummyObjectControl:
<UserControl
x:Class="WinUI3Issues.UserControls.DummyObjectControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:WinUI3Issues.UserControls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Border Height="288" Width="192" BorderThickness="1" BorderBrush="{ThemeResource TextBoxBorderThemeBrush}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="16" Text="{x:Bind Path=Title, Mode=OneWay}"></TextBlock>
</Grid>
</Border>
ItemsRepeaterScrollIssueViewModel:
public class ItemsRepeaterScrollIssueViewModel : BaseViewModel
{
public ObservableCollection<DummyObject> DummyObjects { get; set; }
public ItemsRepeaterScrollIssueViewModel()
{
this.DummyObjects = new ObservableCollection<DummyObject>();
for (var i = 1; i <= 100; i++)
{
this.DummyObjects.Add(new DummyObject(){ Name = $"Object_{i}"});
}
}
}
DummyObject.cs:
public class DummyObject
{
public string Name { get; set; }
}
ViewModelLocator.cs:
public class ViewModelLocator
{
public ItemsRepeaterScrollIssueViewModel ItemsRepeaterScrollIssueViewModel => IocKernel.Get<ItemsRepeaterScrollIssueViewModel>();
public XamlCommandBindingIconSourceIssueViewModel XamlCommandBindingIconSourceIssueViewModel => IocKernel.Get<XamlCommandBindingIconSourceIssueViewModel>();
}
Do any of you know if I might be doing something wrong or if this is a legit bug in WinUI 3?
OK, I got help on Github, the issue was that my dependency properties were not marked as static, another issue was that I didn't set the x:Bind mode to OneWay in my UserControl.

How can I select an item in a wpf combobox when it is a prefix of a previous item?

I'll start with my code example. It's a WPF Application.
MainWindow.xaml:
<Window x:Class="DemoComboBoxProblem.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:DemoComboBoxProblem"
mc:Ignorable="d"
Title="MainWindow" Height="60" Width="200">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ComboBox Name="CB0" Grid.Column="0" Width="60">
<ComboBoxItem>CRLF</ComboBoxItem>
<ComboBoxItem>CR</ComboBoxItem>
<ComboBoxItem>LF</ComboBoxItem>
<ComboBoxItem>LFCR</ComboBoxItem>
</ComboBox>
<ComboBox Name="CB1" Grid.Column="1" Width="60">
<ComboBoxItem>CRLF</ComboBoxItem>
<ComboBoxItem>AA</ComboBoxItem>
<ComboBoxItem>BB</ComboBoxItem>
<ComboBoxItem>LFCR</ComboBoxItem>
</ComboBox>
</Grid>
</Window>
MainWindow.xaml.cs:
using System.Windows;
namespace DemoComboBoxProblem
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
CB0.Text = "CR";
CB1.Text = "AA";
}
}
}
I want to programatically select the item "CR" in CB0 and the item "AA" in CB1.
When I run this, CB0 displays nothing and (I assume) no item is selected in it. CB1 correctly displays and has selected "AA". I think this has something to do with "CR" being a prefix of "CRLF". I can get it to work if I change the order of the items, but I'm wondering: what is the correct way to make it work with the items in the order given?
Thanks
Try this, add SelectedValuePath = "Content" to the combobox properties.
<ComboBox Name="CB0" Grid.Column="0" Width="60" SelectedValuePath="Content">
<ComboBoxItem>CRLF</ComboBoxItem>
<ComboBoxItem>CR</ComboBoxItem>
<ComboBoxItem>LF</ComboBoxItem>
<ComboBoxItem>LFCR</ComboBoxItem>
</ComboBox>
in the code use:
CB0.SelectedValue = "CR";
CB1.SelectedValue = "AA";

How to get WPF Window to autosize to content and no more

I have a dialog containing 2 TextBlocks, a Progress Bar and a cancel Button.
Here 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:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication4"
mc:Ignorable="d"
Title="MainWindow" Height="Auto" Width="200">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock x:Name="txtFirst" Grid.Row="0" Margin="5" TextWrapping="Wrap">This is a really really really really long string that wraps</TextBlock>
<TextBlock x:Name="txtSecond" Grid.Row="1" Margin="5" Text="A Shorter string" TextWrapping="Wrap" MaxWidth="200"/>
<ProgressBar x:Name="prgProgress" Grid.Row="2" Margin="5" Height="20" />
<Button x:Name="btnCancel" Grid.Row="3" Margin="5" Height="25" Width="50"/>
</Grid>
</Window>
I would like the Window not to have a fixed height but auto adjust its height based on the size of its children and no more, but can’t see a way to do this. At the moment when I don’t assign anything to the Window’s height, it seems to adopt a height that is much bigger that the content.
Not sure why, or where it gets height value from? If I set Windows Height = “Auto” I get the same thing. All the heights for the RowDefinitions are set to “Auto”, which I take to mean ‘set row height to be row child height’.
You need to use SizeToContent property, check the msdn link.
Example:
<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"
…
SizeToContent="WidthAndHeight">

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