[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());
Related
I'm building a C# WPF app (for learning purposes) that draws a linked list based on the data input by the user. I've created AddItem/DeleteItem buttons and corresponding text boxes. Wen user enters an item and Presses Add Item button, the corresponding element is to be drawn, with red line separaters between two elements.
I'm using GridView to display the linked list elements.
Corresponding XAML code is below :
<Grid x:Name="ListDrawGrid">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="2*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
</Grid>
I'm currently using C# code to populate data into these elements like below. The below function is called whenever "Add" Button is pressed and new data is inserted into the linked list (ILinkedList is the interface to my custom LinkedList class which maintains the actual list).
public void DrawList(ILinkedList list)
{
int col_index = 0;
int row_index = 1;
GridDrawArea.Children.Clear();
foreach (var i in list)
{
if (col_index >= MaxCols-1)
{
break;
}
TextBlock t = new TextBlock()
{
Text = i,
FontSize = 15,
FontWeight = FontWeights.Bold,
//Width = 15,
HorizontalAlignment = HorizontalAlignment.Left,
//VerticalAlignment = VerticalAlignment.Stretch
};
Grid.SetRow(t,row_index);
Grid.SetColumn(t, col_index);
col_index++;
GridDrawArea.Children.Add(t);
Path line = new Path
{
HorizontalAlignment = HorizontalAlignment.Stretch,
// VerticalAlignment = VerticalAlignment.Stretch,
Stroke = Brushes.Red,
StrokeThickness = 4,
Visibility = Visibility.Visible,
Stretch = Stretch.Fill,
};
LineGeometry lg = new LineGeometry();
lg.StartPoint = new Point(0,col_index);
lg.EndPoint = new Point (0,col_index + 1);
line.Data = lg;
Grid.SetRow(line, row_index);
Grid.SetColumn(line, col_index);
col_index++;
GridDrawArea.Children.Add(line);
}
TextBlock tnull = new TextBlock()
{
Text = "NULL",
FontSize = 15,
//FontWeight = FontWeights.Bold,
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Stretch,
//Width = 15,
};
Grid.SetRow(tnull, row_index);
Grid.SetColumn(tnull, col_index);
GridDrawArea.Children.Add(tnull);
}
But I feel this is not the correct way of doing things. I'm looking for a way to bind the Grid to the linked list backend code such that, the data is updated whenever a new element is added. If I've to do the same using Data Binding, how should I go about it ? If you need any other information from my end , please let me know.
NOTE: ListDrawGrid and GridDrawArea are the same. I've two different vars as they are in different classes. ListDrawGrid is in the main....xaml.cs and GridDrawArea is in another class and it's initialized with ListDrawGrid at init time.
Let's say I have:
<Grid Name="paramGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBox Grid.Row="0" Grid.Column="0"/>
<TextBox Grid.Row="1" Grid.Column="0"/>
</Grid>
I am aware of how to add rows/columns such as:
paramGrid.RowDefinitions.Add(new RowDefinition());
TextBox tb = new TextBox();
tb.Text = "Sample";
tb.Name = "textBox";
paramGrid.Children.Add(tb);
Grid.SetColumn(tb, 0);
Grid.SetRow(tb, 2);
The above adds a TextBox to the new row.
My question is: How would I go about accessing it now? I need to query the .Text property of the TextBox on the new row.
Keep a ref to the textbox:
private TextBox m_Tb;
...
m_Tb = new TextBox();
m_Tb.Text = "Sample";
m_Tb.Name = "textBox";
....
something something = m_Tb.Text;
Find it in the grid's Children collection:
var tb = (TextBox)paramGrid.Children[0];
something something = tb.Text;
Obviously [0] will only work if the text box is either the only child in the grid or the first one.
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);
}
Customizing My app W10 Template from AppStudio
Hello everyone, I’m new to programming and I wanted to make a Windows App just for fun, so far it looks good, however. I have a problem (mostly because I don’t know what I’m doing).
But I want the RSS feed to open Edge instead of the feed view (second page after you click on a feed icon)
I found the config file for the rss feed ( I called it news) but I don’t know how to make it open a new window on edge .
The code is located at:
Sections\NewsConfig.cs
Update: This is the full original code:
using System;
using System.Collections.Generic;
using AppStudio.DataProviders;
using AppStudio.DataProviders.Core;
using AppStudio.DataProviders.Rss;
using AppStudio.Uwp.Actions;
using AppStudio.Uwp.Commands;
using AppStudio.Uwp.Navigation;
using MyWindows10App.Config;
using MyWindows10App.ViewModels;
namespace MyWindows10App.Sections
{
public class NewsConfig : SectionConfigBase<RssDataConfig, RssSchema>
{
public override DataProviderBase<RssDataConfig, RssSchema> DataProvider
{
get
{
return new RssDataProvider();
}
}
public override RssDataConfig Config
{
get
{
return new RssDataConfig
{
Url = new Uri("https://localhost:804514/feed")
};
}
}
public override NavigationInfo ListNavigationInfo
{
get
{
return NavigationInfo.FromPage("NewsListPage");
}
}
public override ListPageConfig<RssSchema> ListPage
{
get
{
return new ListPageConfig<RssSchema>
{
Title = "News",
LayoutBindings = (viewModel, item) =>
{
viewModel.Title = item.Title.ToSafeString();
viewModel.SubTitle = item.Summary.ToSafeString();
viewModel.Description = item.Summary.ToSafeString();
viewModel.Image = item.ImageUrl.ToSafeString();
},
NavigationInfo = (item) =>
{
return null;
}
};
}
}
public override DetailPageConfig<RssSchema> DetailPage
{
get
{
var bindings = new List<Action<ItemViewModel, RssSchema>>();
var actions = new List<ActionConfig<RssSchema>>
{
};
return new DetailPageConfig<RssSchema>
{
Title = "News",
LayoutBindings = bindings,
Actions = actions
};
}
}
public override string PageTitle
{
get { return "News"; }
}
}
}
Update 2: here is the XAML from the List page
<Page
x:Class="MyWindows10App.Views.NewsListPage"
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:was_actions="using:AppStudio.Uwp.Actions"
xmlns:was_commands="using:AppStudio.Uwp.Commands"
xmlns:was_controls="using:AppStudio.Uwp.Controls"
xmlns:layouts="using:MyWindows10App.Layouts"
xmlns:list_layouts="using:MyWindows10App.Layouts.List"
xmlns:controls="using:MyWindows10App.Layouts.Controls"
xmlns:vm="using:MyWindows10App.ViewModels"
xmlns:triggers="using:MyWindows10App.Triggers"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
d:DataContext="{d:DesignData Source=/Assets/Design/DesignData.json, Type=vm:DesignViewModel, IsDesignTimeCreatable=true}"
mc:Ignorable="d">
<Grid Background="{StaticResource AppBackground}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="15"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid Grid.Row="0" Grid.ColumnSpan="2" Background="{StaticResource AppBarBackground}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Height="48"/>
<TextBlock Grid.Row="0" Grid.Column="0" Margin="{Binding ViewModel.PageTitleMargin}" Text="{Binding ViewModel.PageTitle}" Foreground="{StaticResource AppBarForeground}" FontSize="21" VerticalAlignment="Center" HorizontalAlignment="Left" TextTrimming="WordEllipsis" MaxLines="1"/>
<was_actions:ActionsCommandBar
x:Name="appBar"
ActionsSource="{Binding ViewModel.Actions}" Style="{StaticResource WasCommandBarStyle}"
Foreground="{StaticResource AppBarForeground}"
IsVisible="{Binding ViewModel.HasActions}"
Background="{StaticResource AppBarBackground}"
Grid.Row="{Binding ViewModel.AppBarRow}"
Grid.Column="{Binding ViewModel.AppBarColumn}"
Grid.ColumnSpan="{Binding ViewModel.AppBarColumnSpan}">
</was_actions:ActionsCommandBar>
<ProgressBar Grid.Row="1" Grid.ColumnSpan="2" Height="3" Margin="0,6,0,6" IsIndeterminate="True" Foreground="{StaticResource PageTitleForeground}" Visibility="{Binding ViewModel.IsBusy, Converter={StaticResource BoolToVisibilityConverter}, FallbackValue=Collapsed}"/>
<was_controls:ErrorNotificationControl Grid.ColumnSpan="2" x:Uid="ListErrorNotificationControl" Grid.Row="2" ErrorVisibility="{Binding ViewModel.HasLoadDataErrors, Converter={StaticResource BoolToVisibilityConverter}}" ErrorColor="{StaticResource PageTitleForeground}" Margin="10,0,18,0"/>
<list_layouts:ListBigHorizontalCardBox Grid.Row="3" Grid.ColumnSpan="2" DataContext="{Binding ViewModel}" ItemsSource="{Binding Items}" ItemClickCommand="{Binding ItemClickCommand}" OneRowModeEnabled="False" Margin="19,0,12,0" />
<controls:DataUpdateInformationControl Grid.ColumnSpan="2" Grid.Row="4" LastUpdateDateTime="{Binding ViewModel.LastUpdated}" Color="{StaticResource PageTitleForeground}" Margin="8,4,8,4" HorizontalAlignment="Left" HasLocalData="{Binding ViewModel.HasLocalData}"/>
</Grid>
</Page>
In UWP apps, While performing navigating you can use URI scheme or recommend any app to use that URI to open with.
You can use the http URI scheme to launch default web browser as follows
// The URI to launch
var uriFeed = new Uri(#"http://www.myblogfeed.com");
// Launch the URI
var success = await Windows.System.Launcher.LaunchUriAsync(uriFeed);
when launching any URI, you can also pass in LaucherOptions obect, where you can specify the preferredApplication for URI to launch it. Here is the example from a msdn page.
// Set the recommended app
var options = new Windows.System.LauncherOptions();
options.PreferredApplicationPackageFamilyName = "Contoso.URIApp_8wknc82po1e";
options.PreferredApplicationDisplayName = "Contoso URI Ap";
// Launch the URI and pass in the recommended app
// in case the user has no apps installed to handle the URI
var success = await Windows.System.Launcher.LaunchUriAsync(uriContoso, options);
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.