I'm developing an UI for Raspberry PI using Universal Windows Application WPF.
I have to columns:
<Grid.ColumnDefinitions>
<ColumnDefinition Width="400"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid Column="0" name="Column0">
...
</Grid>
<Grid Column="1" name="Column1">
...
</Grid>
and I have a button which do some stuff and after finish the operation, I want to hide first column and second one I want to fill to entire window.
I did this:
private async void DisplaySomething_Click( object sender, RoutedEventArgs e )
{
if( string.IsNullOrWhiteSpace( City.Text ) ) {
return;
}
// do some stuff
Column0.Visibility = Visibility.Collapsed;
Column1.Width = MyPage.ActualWidth;
}
But apparently the second column doesn't fit automatically to entire windows width. It preserve same width even first column is collapsed and second one has * column width
Why ? Where's my mistake ?
<ColumnDefinition Width="400"></ColumnDefinition>
The first column is not collapsed because it still has the Width set to 400. You have to set its Width to 0 when you are collapsing the content of the first column so the second column will be automatically expanded to full width.
Also as #Mogzol said, you should use the attached property Grid.Column when setting in which column the control will be displayed.
XAML:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="CD_Column0" Width="400"></ColumnDefinition>
<ColumnDefinition x:Name="CD_Column1" Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid x:Name="Gr_Column0" Grid.Column="0">
...
</Grid>
<Grid x:Name="Gr_Column1" Grid.Column="1">
...
</Grid>
</Grid>
C#:
private async void DisplaySomething_Click( object sender, RoutedEventArgs e )
{
if( string.IsNullOrWhiteSpace( City.Text ) ) {
return;
}
// do some stuff
Gr_Column0.Visibility = Visibility.Collapsed;
CD_Column0.Width = new GridLength(0);
}
Related
[enter image description here][1]I want to make an application that shows all files in a folder as buttons, so I can open them from the application. So they are getting added dynamically. But I have a problem: I need to show them like a grid, side by side. And if there are more than 9 files it needs to scroll down. I have tried with the layout:
<Grid Name="buttonGrid">
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
<Grid Height="450" Width="800" Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
</Grid>
</ScrollViewer>
</Grid>
And I C#:
public partial class PlayGame : Page
{
public PlayGame()
{
InitializeComponent();
AddButtons();
}
//Add buttons to grid
private void AddButtons()
{
var folderName = $"{AppDomain.CurrentDomain.BaseDirectory}games";
if (!Directory.Exists(folderName))
{
Directory.CreateDirectory(folderName);
}
var allFiles = Directory.GetFiles(folderName);
foreach (string fileName in allFiles)
{
var fi = new FileInfo(fileName);
Button newBtn = new Button
{
Content = fi.Name,
Name = "Button" + fi.Name.Replace(".", "_"),
BorderThickness = new Thickness(0)
};
Grid.SetRow(newBtn, 0);
Grid.SetColumn(newBtn, 0);
newBtn.Click += OpenFile;
buttonGrid.Children.Add(newBtn);
}
}
}
And it works partly... The buttons are getting added, and they work, but they are stacked on each other. So how would i fix that?
I want it like this: https://i.stack.imgur.com/6EUKS.png
But dynamically for each file, there is in a folder. And if there are more than 9 files extend downwards so the scrollviewer comes into action.
Try using
<ScrollViewer Height="300">
<WrapPanel Name="listView" Orientation="Horizontal">
</WrapPanel>
</ScrollViewer>
Your very close.
Try increasing the column
Grid.SetColumn(newBtn, i);
for every iteration.
Then you can also set the row
Grid.SetRow(newBtn, i % 3);
to add a new row every three buttons.
Now if you want a new row you can add it with this command:
buttonGrid.RowDefinitions.Add(new RowDefinition());
My goal is to programmatically set a DockPanel size.
I want it to span from Grid.Column=1, Grid.Row=1, Grid.RowSpan=5
And I know hot to set it statically in xaml, but not in c#.
Explanation to code: In xaml I made a 1row 1 column grid with some textfields and a button in the DockPanel. In when I press the button it should create a grid with as many column/rows as I wrote in the textfields. Then name each column and each row. And know I want to create a Dockpanel on some of these fields but for that I must define where it starts and how far it spans. This is where the problem is.
here is my xaml code how I made it:
<Grid Name="MainWindowGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Name="DockPanel"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<DockPanel Background="LightSalmon" Grid.Row="0" Grid.Column="0" Grid.RowSpan="8">
<StackPanel>
<TextBox Name="txtColums" Text="16"/>
<TextBox Name="txtRows" Text="8"/>
<TextBox Name="txtWindowHeight" Text="800"/>
<TextBox Name="txtWindowWidth" Text="1600"/>
<Button x:Name="ButtonCreate" Content="Create" Click="ButtonCreate_Click"/>
</StackPanel>
</DockPanel>
<ContentControl Content="{Binding}"/>
</Grid>
And my C# code what I have so far:
Methods Methods = new Methods();
Methods.CreateField(MainWindowGrid, txtColums, txtRows, txtWindowHeight, txtWindowWidth, MainWindow1);
int GridColumnCount = MainWindowGrid.ColumnDefinitions.Count;
int GridRowCount = MainWindowGrid.RowDefinitions.Count;
for (int a = 1; a < GridColumnCount; a++)
{
MainWindowGrid.ColumnDefinitions.ElementAt(a).Name = "C" + a;
}
for (int a = 1; a < GridRowCount; a++)
{
MainWindowGrid.RowDefinitions.ElementAt(a).Name = "R" + a;
}
var converter = new System.Windows.Media.BrushConverter();
var brush1 = (Brush)converter.ConvertFromString("#FFFFFFF0");
DockPanel myDockPanel = new DockPanel();
myDockPanel.Background = brush1;
myDockPanel.
At the very end I want to be able to set at which row/column the dockpanel should be and then span it, but I sadly do not know how.
You could use the following methods to set the Grid.Column, Grid.Row and Grid.RowSpan attached properties of myDockPanel:
Grid.SetColumn(myDockPanel, 1); //= <DockPanel ... Grid.Column = "1"
Grid.SetRow(myDockPanel, 1); //= <DockPanel ... Grid.Row = "1"
Grid.SetRowSpan(myDockPanel, 8); //= <DockPanel ... Grid.RowSpan = "8"
I'm pretty stuck right now, i'm gonna explain my problem and what i want.
In my solution i have a mainWindow, in that MainWindow i call the first userControl Who is situated in an userControlLibrary. I'ts a menu with button. I want when i click on the first button of the first userControl, i want put the visibility of the second usercontrol to visible (too situated in the userControlLibrary). But i try many things but no one works.
The first userControl is UC_MenuSlider and UC_Start_Study is the second who have to be visibile after click on the button on the first one. At launch UC_Start_Study is hidden.
This is a part of the code of my Mainwindow:
<Grid Name="MainGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<UserControlLibrary:UC_StartStudy x:Name="UC_Start_Study" Grid.Column="1" Height="Auto" Width="Auto" Margin="70 0 0 0" Visibility="Hidden"/>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.1*" MaxWidth="240" MinWidth="240" />
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<UserControlLibrary:UC_MenuSlider x:Name="UC_MenuSlider" Grid.Column="0"/>
</Grid>
</Grid>
A part of the code of my first UserControl (UC_MenuSlider):
<Grid Name="Grid_Menu" HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button x:Name="Start_Study" Grid.Row="0" Grid.Column="0" Margin="0" Content="Start Study" FontSize="16" Click="Start_Study_Click">
</Button>
</Grid>
At first a basic event,just an event click in my first userControl. with code behind like that:
public void Start_Study_Click(object sender, RoutedEventArgs e)
{
var startStudy = new UserControlLibrary.UC_StartStudy();
startStudy.Visibility = Visibility.Visible;
}
Don't works. Then i use 'RoutedEvent' But I don't really understand who it works.
I hope my question was enough clear, thanks in advance for your anwsers
The problem is because you are creating a new UC_StartStrudy and set its Visibility to Visible. What you really need is to set Visibility of the one in your XAML: UC_Start_Study
public void Start_Study_Click(object sender, RoutedEventArgs e)
{
UC_Start_Study.Visibility = Visibility.Visible;
}
And you could also use XAML databinding the Visibility property of your UC_StartStrudy, and set its value in your code:
XAML:
<Window.Resourses>
<BooleanToVisibilityConverter x:Key="BooltoVisible" />
</Window.Resourse>
.....
<UserControlLibrary:UC_StartStudy x:Name="UC_Start_Study" Grid.Column="1" Height="Auto" Width="Auto" Margin="70 0 0 0" Visibility="{Binding IsUCStartStudyVisible, Converter={StaticResource BooltoVisible}}"/>
Code (remember to implement INotifyPropertyChanged ):
//implement INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChange(String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
//property for data binding
private bool _isucstartstudyvisible = false;
public bool IsUCStartStudyVisible
{
get{return _isucstartstudyvisible;}
set{_isucstartstudyvisible=value; RaisePropertyChange("IsUCStartStudyVisible");}
}
//your event to change the visibility
public void Start_Study_Click(object sender, RoutedEventArgs e)
{
IsUCStartStudyVisible=true;
}
I don't understand why you are taking a new instance of UC_StartStudy() as you have already added this in your MainWindow.
Can't you simply turn the visibility of UC_Start_Study as visible within the code.
Let me show you how you can do this.
try
public void Start_Study_Click(object sender, RoutedEventArgs e)
{
this.UC_Start_Study.Visibility = Visibility.Visible;
}
All my grids could be small and very big depending on window size but text inside is looking really small on big grid sizes.
My current idea (but I don't know how to realize it yet) is to make Binding for all Grid elements to single font and then change the font size by
override void OnRender(DrawingContext dc) {
depending on window size.
The question is: Is this idea sane and is there other methods for it?
If you have not set the font on inner elements explicitly, they inherit the parent font. So you can change the font size on one of the parent elements (for example the Window itself or the Grid). This changes the font size on all inner elements that has not specified the font size explicitly.
However if your font should be of different sizes, the best solution in my opinion is binding the font size of elements to the font size of the parent window, and using a value converter to do a scale on the font size:
Define a value converter like this:
using System;
using System.Windows.Data;
namespace WPFTest
{
public class FontSizeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null)
return null;
double windowFontSize = (double)value;
var scale = System.Convert.ToDouble(parameter);
return windowFontSize * scale;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
And use it in your xaml:
<Window x:Class="WPFTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:test="clr-namespace:WPFTest"
Title="Window1" Height="300" Width="300" FontSize="20" x:Name="window1">
<Window.Resources>
<test:FontSizeConverter x:Key="fontSizeConverter"/>
</Window.Resources>
<Grid>
<StackPanel Grid.Row="0" Grid.Column="0">
<TextBlock
FontSize="{Binding ElementName=window1, Path=FontSize, Converter={StaticResource ResourceKey=fontSizeConverter}, ConverterParameter=1.5}">
Text 1
</TextBlock>
<TextBlock FontSize="{Binding ElementName=window1, Path=FontSize, Converter={StaticResource ResourceKey=fontSizeConverter}, ConverterParameter=0.7}">
Text 2
</TextBlock>
<TextBlock >Text 3</TextBlock>
</StackPanel>
</Grid>
</Window>
ConverterParameter is used as the scale of the element's font related to the window (specified in ElementName property of the binding).
In this example font of the first TextBlock is 150% of the window font and font of the second TextBlock is 70% of the window. The third TextBlock follows the font size of the window.
I like more this solution as suggested by roberther. It is more aesy and clean.
<Viewbox>
<TextBlock Text="Hello World" />
</Viewbox>
I know this is an old post but it was one of the first things to come up when I searched for the topic, so here is my solution:
I've done this in a project recently for work with text boxes and scaling their content font size relative to the screen. For this I set up an integer value and had font size bound to it.
In my case, my screen height starts at 800x650 and I wanted my font to be size 12 by default so I set the integer value (_ScaledFontSize) to WindowHeight/(650/12).
Everytime the screen size changes, a function is called to recalculate the font size and a property change event is called. This function is where you can add constraints for minimum and maximum font sizes using something simple like:
//Set a minimum font size
if(_ScaledFontSize < 12)
_ScaledFontSize = 12;
In order to enforce this scaled sized, every control that you want to scaled font size on must be bound to the ScaledFontSize property.
Final Result:
Text at application launch
Text at about 1920x1080 (Slightly smaller because not fullscreen)
I was struggling to find something like this for a while and in the end this is what I went with. Luckily the code is pretty simple:
MainWindow.xaml.cs:
using System.Windows;
using System.ComponentModel;
namespace FontScaling
{
public partial class MainWindow : Window, INotifyPropertyChanged
{
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
private int _ScaledFontSize;
public int ScaledFontSize
{
get => _ScaledFontSize;
set => _ScaledFontSize = value;
}
public void PropChange(string name)
{
System.ComponentModel.PropertyChangedEventArgs propertyChangedEvt = new System.ComponentModel.PropertyChangedEventArgs(name);
if (PropertyChanged != null)
{
PropertyChanged.Invoke(this, propertyChangedEvt);
}
}
public MainWindow()
{
InitializeComponent();
_ScaledFontSize = (int)Application.Current.MainWindow.Height / 54;
}
private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
{
_ScaledFontSize = (int)Application.Current.MainWindow.ActualHeight / 54;
PropChange("ScaledFontSize");
}
}
}
MainWindow.xaml:
<Window x:Class="FontScaling.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:FontScaling"
mc:Ignorable="d"
Title="MainWindow" Height="650" Width="800"
SizeChanged="Window_SizeChanged"
Name="_This">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="10*"/>
<RowDefinition Height="10*"/>
<RowDefinition Height="10*"/>
<RowDefinition Height="200*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="15*"/>
<ColumnDefinition Width="10*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="10*"/>
<ColumnDefinition Width="15*"/>
</Grid.ColumnDefinitions>
<TextBlock
VerticalAlignment="Bottom"
Grid.Row="1"
Grid.Column="1"
Text="Non Scaled TextBlock"/>
<TextBox
Grid.Row="2"
Grid.Column="1"
Text="Non Scaled Text"/>
<TextBlock
VerticalAlignment="Bottom"
Grid.Row="1"
Grid.Column="3"
Text="Scaled TextBlock"
FontSize="{Binding ScaledFontSize, ElementName=_This}"/>
<TextBox
Grid.Row="2"
Grid.Column="3"
Text="Scaled TextBox"
FontSize="{Binding ScaledFontSize, ElementName=_This}"/>
</Grid>
</Window>
I want to create a game, where the word is given, but there's one letter missing and you need to choose from one of the letters given below. Being a beginner with C#, I find very difficult to make this work. Right now, I have a word class, which has WordFull, LetterA, LetterB, LetterC, index (where I need to put the letter in) and a CorrectLetter. Then, I load this word object, where I put letter one by one in textboxes and if letter's index in the word (h[e]llo = 1) is equal to the current letter's index property (index = 1), then it displays blank underlined textbox. When you click on that letter, then it checks whether that letter is correct with CorrectLetter property and that's the place where I'm stuck. I want to put that letter in place of empty textbox. But how do I choose it? I think I'm doing something wrong.
TL;DR
I want to make a letter game and I need an advice how to do it.
My XAML grid:
<TabItem Name="zaisti" Header="Vykdyti" IsSelected="True">
<Grid Name="Grid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="7*"/>
<RowDefinition Height="2*"/>
</Grid.RowDefinitions>
<Viewbox Grid.Row="0" Grid.Column="0">
<StackPanel Name="letters" Orientation="Horizontal">
</StackPanel>
</Viewbox>
<Image Grid.Row="0" Grid.Column="1" Name="img" Margin="10" Source="pack://siteoforigin:,,,/pic.jpg"/>
<Grid Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Button.Click="Grid_Click">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Margin="10">
<Button.Content>
<Viewbox>
<Label Name="Option1" Content="{Binding LetterA}"></Label>
</Viewbox>
</Button.Content>
</Button>
<Button Grid.Column="1" Margin="10">
<Button.Content>
<Viewbox>
<Label Name="Option2" Content="{Binding LetterB}"></Label>
</Viewbox>
</Button.Content>
</Button>
<Button Grid.Column="2" Margin="10">
<Button.Content>
<Viewbox>
<Label Name="Option3" Content="{Binding LetterC}"></Label>
</Viewbox>
</Button.Content>
</Button>
</Grid>
Code behind:
public partial class MainWindow : Window
{
List<Word> Words = new List<Word>()
{
... data ...
};
int index = 0;
public MainWindow()
{
InitializeComponent();
pradzia.IsSelected = true;
zaisti.IsEnabled = false;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
zaisti.IsSelected = true;
zaisti.IsEnabled = true;
letters.Children.Clear();
LoadWord(index);
this.DataContext = Words[index];
}
private void Grid_Click(object sender, RoutedEventArgs e)
{
if (index == Words.Count() - 1) return;
MessageBox.Show((((e.Source as Button).Content as Viewbox).Child as Label).Content.ToString());
if ((((e.Source as Button).Content as Viewbox).Child as Label).Content.ToString() == Words[index].LetterCorrect)
{
letters.Children.Clear();
LoadWord(++index);
this.DataContext = Words[index];
}
}
private void LoadWord(int i)
{
int a = 0;
foreach (char l in Words[i].WordFull)
{
TextBlock letter = new TextBlock();
letter.Foreground = new SolidColorBrush(Colors.Gray);
letter.Text = l.ToString();
letter.Margin = new Thickness(2);
if (Words[i].index == a)
{
letter.Text = ((char)160).ToString() + ((char)160).ToString();
// Create an underline text decoration. Default is underline.
TextDecoration myUnderline = new TextDecoration();
// Create a solid color brush pen for the text decoration.
myUnderline.Pen = new Pen(Brushes.Red, 1);
myUnderline.PenThicknessUnit = TextDecorationUnit.FontRecommended;
// Set the underline decoration to a TextDecorationCollection and add it to the text block.
TextDecorationCollection myCollection = new TextDecorationCollection();
myCollection.Add(myUnderline);
letter.TextDecorations = myCollection;
}
a++;
letters.Children.Add(letter);
}
}
}
Word class:
class Word
{
public string WordFull { get; set; }
public string LetterA { get; set; }
public string LetterB { get; set; }
public string LetterC { get; set; }
public string LetterCorrect { get; set; }
public int index { get; set; }
}
Based on what I'm seeing, I would do the following
move the creation of the individual letter elements (including the underline) into their own methods that return the component to display.
Then when the player picks the correct letter,
find the underline element,
remove it from the letters visual control,
and replace it with the the correct letter element.
edit - based on comment
There are several ways of getting to the elements in the Children collection. If you know the actual element,
letters.Children.Remove(element);
will allow you to remove the specified element, or
letters.Children[index];
will work if you know the index.