Loading XAML and displaying it properly - c#

I am able to save the Xaml data and then load it again however it doesnt display as I would like it too, this is what it looks like before loading saved data Before loading saved data However after loading all of the buttons disappear After loading I would like to keep the buttons where they are and only load the saved data into its allocated space. Below is the code any help would be great thanks.
public MainWindow()
{
InitializeComponent();
}
// button and code to save canvas
public void Button_Click(object sender, RoutedEventArgs e)
{
string savedCanvas = XamlWriter.Save(cnv);
File.WriteAllText("canvas.xaml", savedCanvas);
}
// button and code for loading canvas
void Button_Click_1(object sender, RoutedEventArgs e)
{
var savedCanvas = File.ReadAllText("canvas.xaml");
StringReader stringReader = new StringReader(savedCanvas);
XmlReader xmlReader = XmlReader.Create(stringReader);
Canvas readerLoadCanvas = (Canvas)XamlReader.Load(xmlReader);
Content = readerLoadCanvas;
}
private void Button_Click_2(object sender, RoutedEventArgs e)
{
Block b = new Block();
hor.Children.Add(b);
}

welcome to SO! From the code that you've provided, the culprit is this line:
Content = readerLoadCanvas;
What you are doing here is replacing your MainWindow's entire "Content" with the canvas.xaml code, therefore it will replace all of your buttons along with the original canvas. Because I can't see your xaml code (not posted yet), I can't tell what container your Canvas resides in (i.e. Grid, StackPanel, etc.).
But if I were to assume that you put your Canvas inside of a Grid, for example, then I can give you an answer. Example:
<Grid x:Name="mainGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<StackPanel x:Name="PanelOfButtons">
<Button Content="Load" .../>
<Button Content="Save" .../>
</StackPanel>
<Canvas x:Name="cnv" Grid.Column="1" Background="Green">
The answer would be to replace the offending line with this to replace the canvas with your new canvas:
// Remove the original canvas
mainGrid.Children.Remove(cnv);
// Add the new canvas
mainGrid.Children.Add(readerLoadCanvas);

Related

Paragraph mark of UWP RichEditBox is not resized

With this code (Editor.Document.Selection.CharacterFormat.Size = 20;) I change the font size of a UWP RichEditBox in the Page_Loaded-handle. When I start typing some characters, everything works fine. But when I select the paragraph mark and then type something, this text appears in the wrong font size (10.5).
What I've tried is to expand the selection before setting the font size, but it seems that there is no paragraph mark when there's no text. But when the rich edit box is empty and I press Shift+Right Arrow ⟶ (as I would normally select the paragraph mark), the font size is set back to 10.5.
Is there any workaround to prevent that the font size is set back to 10.5 in any case?
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock x:Name="FontSizeBlock" Grid.Row="0"></TextBlock>
<RichEditBox x:Name="Editor" Grid.Row="1" SelectionChanged="HandleRichEditBox_SelectionChanged"></RichEditBox>
</Grid>
public sealed partial class MainPage : Page {
public MainPage() {
this.InitializeComponent();
this.Loaded += Page_Loaded;
}
private void Page_Loaded(object sender, RoutedEventArgs e) {
Editor.Document.Selection.SetRange(0, 1);
Editor.Document.Selection.CharacterFormat.Size = 20;
}
private void HandleRichEditBox_SelectionChanged(object sender, RoutedEventArgs e) {
FontSizeBlock.Text = "FontSize: " + Editor.Document.Selection.CharacterFormat.Size;
}
}
Is there any workaround to prevent that the font size is set back to 10.5 in any case?
For your requirement, you could force font size to 20 when you press Shift+Right. Please refer the following code.
private void HandleRichEditBox_SelectionChanged(object sender, RoutedEventArgs e)
{
FontSizeBlock.Text = "FontSize: " + Editor.Document.Selection.CharacterFormat.Size;
if (Editor.Document.Selection.CharacterFormat.Size == 10.5)
{
Editor.Document.Selection.SetRange(0, 1);
Editor.Document.Selection.CharacterFormat.Size = 20;
}
}
When further investigating my problem, I noted that my issue doesn't occur when there has already been some text in the RichEditBox which was deleted.
Therefore, I have tried to programmatically append, select and remove characters in the Page_Loaded-handle, and this approach worked for me.
private void Page_Loaded(object sender, RoutedEventArgs e) {
// set any character
Editor.Document.SetText(Windows.UI.Text.TextSetOptions.None, "a");
Editor.Document.Selection.Expand(Windows.UI.Text.TextRangeUnit.Paragraph);
Editor.Document.Selection.CharacterFormat.Size = 20;
Editor.Document.SetText(Windows.UI.Text.TextSetOptions.None, "");
}

WPF - How to persist current content when setting the content property

I'm facing a problem where by setting the content property of my window I obviously remove pre-existing content. On all windows I have a dockpanel that I use to pop up help contextual help to the user but this is lost when I set the content property of the window. Therefore I will only see the content for the control I've added and pressing F1 does nothing as the dockpanel does not exist. I don't want to add this dockpanel to every control as it's poor code-reuse so what can I do to keep the dockpanel on the window and add content without overwriting original content of the window?
This is the code where I set the content of the window.
private void btnHelp_Click(object sender, RibbonControlEventArgs e)
{
System.Windows.Window window = new ResizeableWindow()
{
Title = "Help",
Content = new Controls.Help(),
ResizeMode = ResizeMode.NoResize
};
window.ShowDialog();
}
This is code for my Help control it's just a document viewer to read an xps document, this is used by the dockpanel.
public partial class Help : UserControl
{
public Help()
{
InitializeComponent();
string appPath = "path";
XpsDocument doc = new XpsDocument(appPath, FileAccess.Read);
var docx = doc.GetFixedDocumentSequence();
HelpDocViewer.Document = docx;
}
}
This is the xaml of my ResizableWindow containing the Dockpanel
<Window x:Class="Controls.ResizeableWindow"
KeyDown="HelpKeyListen">
<Grid>
<DockPanel x:Name="HelpPanel">
</DockPanel>
</Grid>
</Window>
Here is the code for the resizeable window
public ResizeableWindow()
{
InitializeComponent();
}
private void HelpKeyListen(object sender, KeyEventArgs e)
{
if (e.Key == Key.F1)
{
var HelpControl = new Help();
DockPanel.SetDock(HelpControl, Dock.Right);
HelpPanel.Children.Insert(0, HelpControl);
}
}
Use Placeholders inside the DockPanel instead of replacing the window content:
<DockPanel x:Name="HelpPanel">
<ContentControl x:Name="HelpContent" DockPanel.Dock="Right"/>
<ContentControl x:Name="MainContent"/>
</DockPanel>
Then assign the contents of the contentcontrols as needed
private void HelpKeyListen(object sender, KeyEventArgs e)
{
if (e.Key == Key.F1)
{
HelpContent.Content = new Help();
}
}
Possibly create a new dependency property in ResizeableWindow if you want to provide main content from the outside. Lets say you add a dependency property (visual studio code snipped propdp) named MainContent, then you can bind it as follows:
<DockPanel x:Name="HelpPanel">
<ContentControl x:Name="HelpContent" DockPanel.Dock="Right"/>
<ContentControl x:Name="MainContentPlaceholder" Content="{Binding MainContent,RelativeSource={RelativeSource AnchestorType=Window}}"/>
</DockPanel>
The more appropriate option would be to replace the MainContentPlaceholder by some more WPF/MVVM friendly way to display your contents, but thats out of scope for the question.

How to set width/height in code without breaking Grid star-size?

I have some XAML code like this:
<ScrollViewer VerticalScrollMode="Auto">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid x:Name="g1" Grid.Row="0" Background="Pink"/>
<Grid x:Name="g2" Grid.Row="1" Background="Green"/>
</Grid>
</ScrollViewer>
<Button Content="Update Size" Width="150" Height="50" Click="Button_Click" Margin="105,342,0,248"/>
and code behind:
private void Button_Click(object sender, RoutedEventArgs e)
{
g1.Width = mainGrid.ActualWidth;
g1.Height = mainGrid.ActualHeight / 2;
}
it shows before clicking the button like this:
after clicking the button and drag the window to a bit larger, it looks like this:
so my question is, before clicking the button if you drag the window around the star-sizing works and resize both top/bottom grids as window resizes, however after clicking the buttom, which sets g1 width and height, it breaks star-sizing. how do i bring the star-sizing back to work again after set the width and height?
thanks in advance.
how do i bring the star-sizing back to work again after set the width and height?
After you set the width and height for Grid g1, you broke the auto star-sizing. But you can use the Window.SizeChanged event to monitor the size changing of the application window view instead. When window size changed, dynamically set new height and width for g1 by yourself to fit the parent control mainGrid.
Code like follows will meet you current requirements.
public Strangelaout()
{
this.InitializeComponent();
Window.Current.SizeChanged += Current_SizeChanged;
}
private void Current_SizeChanged(object sender, Windows.UI.Core.WindowSizeChangedEventArgs e)
{
g1.Width = mainGrid.ActualWidth;
g1.Height = mainGrid.ActualHeight / 2;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
g1.Width = mainGrid.ActualWidth;
g1.Height = mainGrid.ActualHeight / 2;
}

Fixed positioning in XAML

I have a Windows Store-style WPF application, and I just added search to it. When I click the Search button in the app bar, I set my FlyoutPresenter containing the SearchBox to Visible. This button is placed in the lower right-hand corner. It works good on computers with keyboards, but I ran into a problem when the virtual keyboard, or InputPane, opens. First, the keyboard covered the box. I solved that problem by checking and adjusting the margin of the box when the box is in focus, but when I scroll the page to the very top and bottom, the control starts moving on the page. Here is my minimal code:
XAML:
<Grid Background="White" x:Name="MainGrid">
<!-- App Bar with Search button -->
<AppBar x:Name="BAppBar" VerticalAlignment="Bottom">
<CommandBar>
<CommandBar.PrimaryCommands>
<AppBarButton Icon="Find" Label="Search" Click="Search_Click"/>
</CommandBar.PrimaryCommands>
</CommandBar>
</AppBar>
<!-- Search button and Close button -->
<FlyoutPresenter VerticalAlignment="Top" Name="SearchPop" Visibility="Collapsed">
<StackPanel Orientation="Horizontal">
<SearchBox Name="Search" GotFocus="Search_Focus" LostFocus="Search_Focus"/>
<AppBarButton Name="SearchClose" Icon="Cancel" Click="Search_Close" />
</StackPanel>
</FlyoutPresenter>
</Grid>
C#:
public partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
// Close app bar, show search box, and set margin to bottom of page
private void Search_Click(object sender, RoutedEventArgs e)
{
BAppBar.IsOpen = false;
SearchPop.Visibility = Windows.UI.Xaml.Visibility.Visible;
SearchPop.Margin = new Thickness(0, MainGrid.ActualHeight - SearchPop.ActualHeight, 0, 0);
}
// Set margin for opening/closing virtual keyboard
private void Search_Focus(object sender, RoutedEventArgs e)
{
Windows.UI.ViewManagement.InputPane.GetForCurrentView().Showing += (s, args) =>
{
double flyoutOffset = (int)args.OccludedRect.Height - SearchPop.ActualHeight;
SearchPop.Margin = new Thickness(0, flyoutOffset, 0, 0);
};
Windows.UI.ViewManagement.InputPane.GetForCurrentView().Hiding += (s, args) =>
{
SearchPop.Margin = new Thickness(0, MainGrid.ActualHeight - SearchPop.ActualHeight, 0, 0);
};
}
// Close search
private void Search_Close(object sender, RoutedEventArgs e)
{
SearchPop.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
}
}
What I need is for the box to not be affected by the user scrolling in the screen. In HTML, this is called Fixed Positioning. I have read that it is not natively possible in XAML, but that there are workarounds. I have read these MSDN and SO links, but they didn't really help:
http://social.msdn.microsoft.com/Forums/en-US/9779328a-a7cd-447d-a4ac-bcc952083f43/fixed-positioning-in-wpf?forum=wpf
http://social.msdn.microsoft.com/Forums/windowsapps/en-US/7349d01d-dc0e-4e1c-9327-df90e00fbebf/how-to-handle-the-appearance-of-the-onscreen-keyboard?forum=winappswithcsharp
Popup control moves with parent
You can simulate the fixed behavior in XAML in a very simple way:
<Grid Background="White" x:Name="MainGrid">
<ContentControl VerticalAligment="Stretch" HorizontalAligment="Stretch">
<!--All other visual controls, the float item will be located over all controls located here, even scrolls viewers-->
</ContentControl>
<!-- Float item -->
<SomeControl>
<!--The control you want be over in the fixed position,
you can set the layout to it, and locate it where you want
just set the Vertical/Horizontal Aligment, margin, height, width-->
</SomeControl>
</Grid>
(Sorry if code sample has some sintax errors, I had write it in the fly)
Also wpf has some controls that are displayed on a layer over all other, this elements are context menus, tooltips and adorners, you also could try them.
I hope this ideas helps.

Performance issues while recalculating ´WriteableBitmap´

Since my issue is rather uncommon and I have not a single clue what could be causing it, I will try to include every code that might have anything to do with it, stripped down to the very essentials to avoid unnecessary clutter.
Basically, I have a TabControl that includes TabItems whoes Contents are custom UserControls.
Those controls are of the following form:
<UserControl>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinition>
<ScrollViewer Height="Auto" HorizontalAlignment="Stretch" Margin="0" Name="scrollViewer11" VerticalAlignment="Stretch" Width="Auto" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"></ScrollViewer>
<ScrollViewer Grid.Column="1" Height="Auto" Name="scrollViewer12" Width="Auto" Margin="0" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto"></ScrollViewer>
<ScrollViewer Grid.Row="1" Height="Auto" Name="scrollViewer21" Width="Auto" Margin="0" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"></ScrollViewer>
<ScrollViewer Grid.Row="1" Grid.Column="1" Height="Auto" Name="scrollViewer22" Width="Auto" Margin="0" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"></ScrollViewer>
</Grid>
</UserControl>
The amount of rows and columns depends on the control used and ranges from a single cell in a 1x1 grid to 6 cells in a 3x2 grid (each contraining the ScrollViewer).
Now to my actual C# code. To each cell the user may add a WriteableBitmap where the code is organized as such:
public partial class MainWindow : Window
{
List<WorkSpace> WorkSpaceList = new List<WorkSpace>();
private WorkSpace currentSpace = null;
//one of the methods that adds to the TabControl, here a 2x2 grid:
private void NewWorkspaceFour(WorkSpace ws)
{
WorkSpaceFour workSpaceFour = new WorkSpaceFour();
for (int i = 0; i < 4; i++)
{
WorkPlace wp = new WorkPlace();
ws.workPlaceList.Add(wp);
switch (i)
{
case 0:
workSpaceFour.scrollViewer11.Content = wp.grid;
break;
case 1:
workSpaceFour.scrollViewer12.Content = wp.grid;
break;
case 2:
workSpaceFour.scrollViewer21.Content = wp.grid;
break;
case 3:
workSpaceFour.scrollViewer22.Content = wp.grid;
break;
}
}
ws.tabItem.Content = workSpace;
tabControlImages.Items.Add(ws.tabItem);
}
//triggered in UI e.g. by moving a Slider
private void NewSettings(object sender, RoutedPropertyChangedEventArgs<double> e)
{
currentSpace.NewSettings((float)(e.NewValue));
}
}
internal class WorkSpace
{
internal delegate void NewSettingHandler(float e);
internal List<WorkPlace> workPlaceList = new List<WorkPlace>();
internal TabItem tabItem = new TabItem();
internal WorkPlace currentPlace = null;
internal NewSettingsHandler NewSettings;
internal WorkSpace()
{
NewSettings += ChangeSettings;
}
internal void ChangeSettings(float newValue)
{
//do something small with newValue
currentPlace.RecalculateImage();
}
//...more methods that would use "newValue" in a different way, thus the delegate
}
internal class WorkPlace
{
internal WriteableBitmap bitmap;
internal Image image = new Image {//settings};
internal Grid grid = new Grid {//settings};
internal Grid gridImage = new Grid {//settings};
internal WorkPlace()
{
grid.Children.Add(gridImage);
gridImage.Children.Add(image);
}
internal void RecalculateImage()
{
//some rather long calculations...
bitmap.WritePixels(...,...,...,...);
image.Source = bitmap;
}
}
Through the program the user can change the tabs to change currentSpace and click on the cells to change the respective currentPlace both simply by change the reference i.e. currentSpace = space, where space refers to the WorkSpace that contains the new selected TabItem.
Now the issue is as follows. When a tab contains a simple 1x1 grid with an image in it and I move the slider, it runs very smoothly. When a tab contains a 3x2 grid and only a single cell of this grid contains a WorkPlace with a bitmap that is not null it works the same. However, when the 3x2 grid is completely filled with "painted" bitmaps and the slider is moved a noticable lag appears, even though only a single of the 6 images is recalculated redrawn. I don't see why this should be the case. It might have something to do with rendering or the object references but I don't know C# well enough to see and issues here.
Hopefully, the code is not too long (I have stripped it down as much as I could) and clear enough. If anything is not, please say so and I will update/add it. In a previous version of this program the UI was basically the same but the recalculation of the images was fairly different but I could never observe this problem.

Categories