I am working on a universal class library , targeted to use UWP apps.
In this am trying to use Content Dialog to get some user input.
All works good in debug, when I pack my library as dll and distribute, the ContentDialog not showing from the app which refers my dll.
I am getting Windows.UI.Xaml.Markup.XamlParseException: XAML parsing failed exception, i got this through log file.
Here is my code
ContentDialog
<ContentDialog
x:Class="xxxx.yyyy.InputContentDialogue"
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"
x:Name="dialog"
Title="Title">
<ContentDialog.Resources>
<Style x:Name="ButtonStyleNoTabFocus" TargetType="Button">
<Setter Property="FocusVisualPrimaryBrush" Value="Transparent" />
<Setter Property="Margin" Value="5"/>
</Style>
</ContentDialog.Resources>
<!-- Content body -->
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Margin="0,20" MinWidth="550">
<StackPanel Orientation="Vertical">
<TextBlock TextWrapping="WrapWholeWords" Margin="5,0,0,10">
shkgdsakjfdhgsajkfdhkasd sadkfjahsdkj asdfjasfdja asdkfjasdf asdkjfnas asdkjfnasd
</TextBlock>
<TextBlock Margin="5,0,0,10">sjkdhfkjsdf sdajfakjdsb sadfkajsdfa.
</TextBlock>
<StackPanel Orientation="Horizontal">
<Button TabIndex="0"
HorizontalAlignment="Center"
Content="hey there"
Style="{StaticResource ButtonStyleNoTabFocus}"
x:Name="btn1"
Click="btn1_Click"
GotFocus="Btn_GotFocus"
LostFocus="Btn_LostFocus"/>
<Button HorizontalAlignment="Center"
Content="Hi"
x:Name="btn2"
Style="{StaticResource ButtonStyleNoTabFocus}"
Click="btn2_Click"
GotFocus="Btn_GotFocus"
LostFocus="Btn_LostFocus"/>
<Button HorizontalAlignment="Center"
Content="Hello"
Style="{StaticResource ButtonStyleNoTabFocus}"
x:Name="btn3"
Click="btn3_Click"
GotFocus="Btn_GotFocus"
LostFocus="Btn_LostFocus"/>
</StackPanel>
</StackPanel>
</Grid>
ContentDialog.cs
public sealed partial class InputContentDialogue : ContentDialog
{
public UserConsentContentDialogue()
{
this.InitializeComponent();
this.Result = -1;
this.Closing += ContentDialogue_Closing;
}
private void ContentDialogue_Closing(ContentDialog sender, ContentDialogClosingEventArgs args)
{
if (args.Result == ContentDialogResult.None && this.Result == -1)
{
args.Cancel = true;
}
}
public int Result { get; set; }
// Handle the button clicks from dialog
private void btn1_Click(object sender, RoutedEventArgs e)
{
this.Result = 0;
// Close the dialog
dialog.Hide();
}
private void btn2_Click(object sender, RoutedEventArgs e)
{
this.Result = 1;
// Close the dialog
dialog.Hide();
}
private void btn3_Click(object sender, RoutedEventArgs e)
{
this.Result = 2;
// Close the dialog
dialog.Hide();
}
private void Btn_GotFocus(object sender, RoutedEventArgs e)
{
Brush _blinkBrush = Application.Current.Resources["SystemControlHighlightAccentBrush"] as SolidColorBrush;
(sender as Button).BorderBrush = _blinkBrush;
}
private void Btn_LostFocus(object sender, RoutedEventArgs e)
{
(sender as Button).BorderBrush = new SolidColorBrush(Colors.Transparent);
}
}
And am creating a new instance and try to show the dialog , like this
internal static async Task<int> ShowMyContentDialog()
{
try
{
InputContentDialogue dialogue = new InputContentDialogue();
await dialogue.ShowAsync();
return dialogue.Result;
}
catch(Exception e)
{
FileOperations.WriteToLogFile("ERROR occurred "+ e.ToString());
}
return -1;
}
Everything works good , if I refer this library in code base.
If I get release dll and refer it from a test app, am getting the xaml parse exception.
Can anyone help me in this.
Thanks in advance.
Everything works good , if I refer this library in code base. If I get release dll and refer it from a test app, am getting the xaml parse exception.
Great question, the problem is your dll file miss Xaml Content. When you compile a dll with xaml file in it, it will be recorded into xxxx.xr.xml files, and those files must be copied as well to the bin directory (BUT NOT Obj folder)of your app with relative path. After build the class library, please check if the bin folder contains dll, pdb, pri and dll resource folder like the following.
For the testing, it will work, if you directly add the dll file where in the class library bin folder to your project reference.
Finally, I found the solution.
Thanks #Nico for the answer, its almost answered the question.
Here is the link which gives you the clear picture about the issue
Missing xaml.xr of a class library file in UWP
Steps
1) Check "Generate library layout" in your project properties
2) While copy your dll from bin/release folder, copy these files too
ClassLibrary1(Class Library name) Folder
ClassLibrary1.xr.xml
2.UserControl.xaml (UserControl XAML file)
ClassLibrary1.dll
ClassLibrary1.pri
Keep all these files in the same folder where you keep your library dll.
Just refer your library dll alone to the referrer project.
All other files will be automatically referred .
Related
The C++ program reads a file, processes the content and safes the result in another file.The filenames have to be typed in the console. The program works fine, but typing the filenames can be pretty unpleasant if the file and the program are not in the same directory.
Therefore I made the C#/WPF windows desktop program.You can open a file browsing your computer. The program puts the filename in a textbox so you can copy it. The same with the output file.
I start both programs, and when the C++ program asks the filename I use the other program to find the filename,copy it and paste it in the console. The same with the output file.
This works fine, but how can I merge the two programs?
Here is the second program:
Layout in xaml:
<Window x:Class="Cx_desktop_for_tracebitmap.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:Cx_desktop_for_tracebitmap"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<StackPanel DockPanel.Dock="Top">
<Label Content="Click input file or output file" ></Label>
<Button Click="input_Click" Content="input file" Name="Button_Input" Width="60" Margin="10" HorizontalAlignment="Left"/>
<Button Click="output_Click" Content="output file" Name="Button_Output" Width="60" Margin="10" HorizontalAlignment="Left"/>
<Label Content="Input Filename" DockPanel.Dock="Top" HorizontalAlignment="Center" ></Label>
<TextBox Name="inputname" Text="" Margin="10" Width="500" DockPanel.Dock="Top" HorizontalAlignment="Center"></TextBox>
<Label Content="Output Filename" DockPanel.Dock="Top" HorizontalAlignment="Center" ></Label>
<TextBox Name="outputname" Text="" Margin="10" Width="500" DockPanel.Dock="Top" HorizontalAlignment="Center"></TextBox>
Button Click="Go_Click" Content="GO" Name="Button_Go "Width="60" Height="60" Margin="10" HorizontalAlignment="Left" Visibility="Hidden"/>
</StackPanel>
</Window>
C# in Mainwindow:
using System.Diagnostics;
using System.Windows;
using Microsoft.Win32;
namespace Cx_desktop_for_tracebitmap
{
/// <summary>
/// find filenames
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private string file_in = "";
private string file_out = "";
private bool BoolIn = false;
private bool BoolOut = false;
private void input_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
if (openFileDialog.ShowDialog() == true)
{
file_in = fix_filename(openFileDialog.FileName);
inputname.Text = file_in;
BoolIn = true;
if (BoolOut) Button_Go.Visibility = Visibility.Visible;
}
}
private void output_Click(object sender, RoutedEventArgs e)
{
SaveFileDialog saveFileDialog = new SaveFileDialog();
if (saveFileDialog.ShowDialog() == true)
{
file_out = fix_filename(saveFileDialog.FileName);
outputname.Text = file_out;
BoolOut = true;
if (BoolIn) Button_Go.Visibility = Visibility.Visible;
}
}
private string fix_filename(string fixme)
{
char quote = (char)34;
string fixed_filename = quote+fixme+quote;
return fixed_filename;
}
private void Go_Click(object sender, RoutedEventArgs e)
{
string arguments = file_in + " " + file_out;
Process pBPM_reader; pBPM_reader = new Process();
pBPM_reader.StartInfo.FileName = #"BMP READER versie 4.exe";
pBPM_reader.StartInfo.Arguments = arguments;
pBPM_reader.Start();
}
}
}
I edited the program to show how I did it:
I added a new button (GO) to start the C++ program.
It is hidden at startup and apears when both files are chozen.
The filenames can contain spaces.
They must be wrapped between quotationmarks.That happens in the fix_filename method
The click on the GO button starts a new Process that runs the C++ program.
The Arguments take only one string, and the arguments are separated bij spaces.
Here is the heather and the first line od the C++ file. It shows how to extract the arguments
int main(int argc, char *argv[])
{
std::vector<std::string> argList(argv, argv + argc);
.
.
.
}
You have to either create a CLI-Intermediate code wrapper assembly that bridges between safe to unsafe code and converts (marshalls) types, etc. This allows you to represent a property C# interface to your C++ code. This blog has some more detailed information.
Or you can try to use P-Invoke to call C++ code from C# directly (see the docs here).
See this stackoverflow question for decision help.
For more information see the CLI documentation, P-Invoke documentation, this blog and this Microsoft forum.
I see some answer about it, suggest use Live Unit Testing feature.
So I don't have Microsoft Enterprise and therefore can't use its Live Unit Testing feature. Tried to create a simple application in order to compile & reload into the WPF container window.
skeleton code look like:
public void RecompileAndReloadPrj ()
{
Grid.Content = null;
ReleaseAsm()
RunMsBuild(targetProject);
Grid.Content = LoadComponetFromAsm(targetASM);
}
Unfortunately getting it to work has turned out to be a bit complicated... Does anyone have ready code that they could post, tips etc, or provide a link?
Yes, before couple years I wrote some code for WPF like you wish. But it's very basic and have a lot of issues around it.
But I suggest you, check the feature of Edit XAML while debugging. It's work well even without breakpoint. Just run project under debugging mode and edit the XAML file, even if your code load it by code behind. Even Save not required.
I list here the code and some comment about it:
MainWindow.xaml
<Window x:Class="RebuildAndReloadWPF.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:RebuildAndReloadWPF"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800" Activated="Window_Activated" >
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition />
</Grid.RowDefinitions>
<Border CornerRadius="6" BorderBrush="Gray" Background="LightGray" BorderThickness="2" >
<StackPanel x:Name="___No_Name_" Background="LightYellow" Orientation="Horizontal">
<Button Click="Button_Click" >Reload</Button>
<CheckBox x:Name="chkReloadOnFocus" VerticalContentAlignment="Center" VerticalAlignment="Center" Content="Reload on focus" Margin="10,0,0,0"/>
<TextBlock x:Name="txtIndicator" VerticalAlignment="Center" Margin="10,0,0,0"/>
<Border x:Name="elmJustNowIndicator" BorderThickness="1" BorderBrush="Black" Background="Orange" CornerRadius="5" Height="21" Width="76" Visibility="Hidden" Margin="10,0,0,0">
<TextBlock Text="Just now" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</StackPanel>
</Border>
<ScrollViewer x:Name="PlaceHolder" Grid.Row="1"/>
</Grid>
</Window>
MainWindow.xaml.cs
using Microsoft.Build.BuildEngine;
using System;
using System.IO;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Threading;
namespace RebuildAndReloadWPF
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
const string projectPath = #"C:\...\Some-Project.csproj";
const string libFileName = "Some-Lib.dll";
const string ClassName = "NameSpace.UserControlName";
private string projectFileName;
private string projectDirectoryPath;
private string projectBinPath;
private string logFilePath;
private string appDirectoryPath;
private DispatcherTimer indicatorTimer = new DispatcherTimer();
public MainWindow ()
{
projectFileName = Path.GetFileName(projectPath);
projectDirectoryPath = Path.GetDirectoryName(projectPath);
projectBinPath = projectDirectoryPath + #"\bin\Debug";
logFilePath = projectDirectoryPath + #"\bin\Debug\build.log";
appDirectoryPath = AppDomain.CurrentDomain.BaseDirectory;
indicatorTimer = new DispatcherTimer();
indicatorTimer.Interval = TimeSpan.FromMilliseconds(4000);
indicatorTimer.Tick += ( sender, e ) =>
{
elmJustNowIndicator.Visibility = Visibility.Hidden;
indicatorTimer.IsEnabled = false;
};
InitializeComponent();
}
public void ReloadContainer ()
{
PlaceHolder.Content = null;
bool result = RunMsBuild();
if (!result)
{
txtIndicator.Text = "Compile error, see in log file. Compile fail at: " + DateTime.Now.ToLongTimeString();
txtIndicator.Foreground = Brushes.Red;
return;
}
else
{
txtIndicator.Text = "Last build at: " + DateTime.Now.ToLongTimeString();
txtIndicator.Foreground = Brushes.Green;
}
try
{
File.Copy(projectBinPath + #"\" + libFileName, appDirectoryPath + libFileName, true);
}
catch (Exception ex)
{
MessageBox.Show("Can't copy compiled lib file: " + ex.Message);
throw;
}
elmJustNowIndicator.Visibility = Visibility.Visible;
indicatorTimer.IsEnabled = false;
indicatorTimer.IsEnabled = true;
try
{
PlaceHolder.Content = AsmLoad();
}
catch (Exception ex)
{
MessageBox.Show("Laod assembly error" + ex.Message);
}
GC.Collect();
}
public bool RunMsBuild ()
{
Engine eng = new Engine();
FileLogger logger = new FileLogger();
logger.Parameters = "logfile=" + logFilePath;
eng.RegisterLogger(logger);
bool bb = eng.BuildProjectFile(projectPath);
eng.UnregisterAllLoggers();
return bb;
}
public FrameworkElement AsmLoad ()
{
byte[] assemblyFileBUffer = File.ReadAllBytes(appDirectoryPath + #"\" + libFileName);
Assembly asm = AppDomain.CurrentDomain.Load(assemblyFileBUffer);
ContentControl container = (ContentControl)asm.CreateInstance(ClassName);
return (FrameworkElement)container.Content;
}
private void Window_Activated ( object sender, EventArgs e )
{
if (chkReloadOnFocus.IsChecked == true)
ReloadContainer();
}
private void Button_Click ( object sender, RoutedEventArgs e )
{
ReloadContainer();
}
}
}
Comments:
The above code is work only against UserControl class. You can
expand code to support also with Windows and Panel.
The above code make rebuild only when window of our app activated
(focus). You can expand it to respond file save. By use with
FileSystemWatcher. Notice, the watcher run event for every file. So
you need wait after all event burst end (brobebly by timer), and
also Suggest to configure Visual Studio to make always SaveALL for
Ctr+S key combination.
Microsoft replace Microsoft.Build.BuildEngine with newest assembly
and suggest use with new Microsoft.Build. I realize that newest have
problem find the newest Tools (MSBuild.exe) like version 15.0. You
probably will get error that need workaround:
Microsoft.Build.Exceptions.InvalidProjectFileException: 'The tools
version "15.0" is unrecognized. Available tools versions are "12.0",
"14.0", "2.0", "3.5", "4.0".'
Dotnet can't release assembly after loading it dynamically. Work
around not worth the effort. I check the above code and I run it
with loop, the consume RAM is better than I was imagined. And also,
I realize that Core 3.0 have solution for that. So if you like this
code, I suggest you try emigrate it to core 3.0
Performance. I not try it on real project. But if you have spare RAM
and strong CPU I believe that work well for small project, and not
have delay more than half of second. I compare it against start
debugging after code change. The Visual studio have a long delay to
enter debug mode and exit. So may you get significate improvement.
By the way, if you copy the debug info file (.pdb) as well as lib
file, the VS will open the source file when runtime error occur on
target projects. But this file get Lock. And next reload Fail (It's
weird, but according my check, it's not happened if target project
is VB).
If you really want develop with this approach. You need build your
target app as collection of small project. You can Embedded the
below code in your target project and open the container window when
you on develop mode. You can add Cache system for all data read from
files or outside resources like Databases. And Build system that
allow jump the reload directly to some point in the Interface.
I'd like to display a content dialog box that has more than the traditional Primary and Secondary results. Since I can't override the ContentDialogResult enum and add options to that property, it seems my only choice may be to create my own custom control that works similarly to a ContentDialog.
For additional context: Often, one might see a Dialog box show up during a computer/app operation, when the action is redundant, i.e. copying files to a folder, the computer generally offers a dialog box with not 2 options, but 4. -> "Yes to All", "No to All", "Yes", "No". I can't seem to find any cookie cutter ways to take advantage of this seemingly common practice.
I'd like to use it just the same as a normal Content Dialog like so:
var dialog = new MyCustomContentDialog();
var result = dialog.ShowAsync();
and then return an enum just as the normal ContentDialog but instead have it return 1 of 4 options, not just 2.
Any help or recommendations would be great. Thanks.
I'd like to display a content dialog box that has more than the traditional Primary and Secondary results.
The ContentDialog has 2 built-in buttons(the primary/secondary button) that let a user respond to the dialog. If you want more buttons to let the user to respond to the dialog, you should be able to achieve this by including these buttons in the content of the dialog.
Following is a simple sample shows how to create and use a custom dialog with 3 button:
MyCustomContentDialog.xaml
<ContentDialog
x:Class="ContentDialogDemo01.MyCustomContentDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ContentDialogDemo01"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Name="dialog"
Title="Delete">
<!-- Content body -->
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Margin="0,20">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="200" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Grid.ColumnSpan="3" Text="Delete file A?" Margin="5" />
<Button Grid.Row="1" Content="Yes" x:Name="btn1" Click="btn1_Click" Margin="5,0" Width="100" />
<Button Grid.Row="1" Grid.Column="1" Content="No" x:Name="btn2" Click="btn2_Click" Margin="5,0" Width="100" />
<Button Grid.Row="1" Grid.Column="2" Content="Cancle" x:Name="btn3" Click="btn3_Click" Margin="5,0" Width="100" />
</Grid>
</ContentDialog>
MyCustomContentDialog.xaml.cs
namespace ContentDialogDemo01
{
// Define your own ContentDialogResult enum
public enum MyResult
{
Yes,
No,
Cancle,
Nothing
}
public sealed partial class MyCustomContentDialog : ContentDialog
{
public MyResult Result { get; set; }
public MyCustomContentDialog()
{
this.InitializeComponent();
this.Result = MyResult.Nothing;
}
// Handle the button clicks from dialog
private void btn1_Click(object sender, RoutedEventArgs e)
{
this.Result = MyResult.Yes;
// Close the dialog
dialog.Hide();
}
private void btn2_Click(object sender, RoutedEventArgs e)
{
this.Result = MyResult.No;
// Close the dialog
dialog.Hide();
}
private void btn3_Click(object sender, RoutedEventArgs e)
{
this.Result = MyResult.Cancle;
// Close the dialog
dialog.Hide();
}
}
}
Here is the code to show the custom dialog and use returned custom result:
private async void ShowDialog_Click(object sender, RoutedEventArgs e)
{
// Show the custom dialog
MyCustomContentDialog dialog = new MyCustomContentDialog();
await dialog.ShowAsync();
// Use the returned custom result
if (dialog.Result == MyResult.Yes)
{
DialogResult.Text = "Dialog result Yes.";
}
else if (dialog.Result == MyResult.Cancle)
{
DialogResult.Text = "Dialog result Canceled.";
}
else if (dialog.Result == MyResult.No)
{
DialogResult.Text = "Dialog result NO.";
}
}
Here is the entire sample. Following is the output:
Just for completeness - the ContentDialog class by default actually offers three buttons - Primary, Secondary and Close. Close is what is triggered when the user presses escape, but if you set CloseButtonText the button will show up as the third button in the dialog's footer.
I have a little problem with saving some properties of my Buttons. The Buttons are small and with a variety of colors. When i press one button, some specified colors are changing... and i want to save them for the next start up. The textbox values i can save them but this ...i can't.
Code:
public MainWindow()
{
InitializeComponent();
//blueColor.RaiseEvent(new RoutedEventArgs(Button.ClickEvent));
//this.Property = Properties.Settings.Default.userColor;
}
private void blueColor_Click(object sender, RoutedEventArgs e)
{
var bc = new BrushConverter();
Main.Background = (Brush)bc.ConvertFrom("#FF007CE4");
startButton.Foreground = (Brush)bc.ConvertFrom("#FF007CE4");
closeButton.Foreground = (Brush)bc.ConvertFrom("#FF007CE4");
Properties.Settings.Default.userColor = true;
Properties.Settings.Default.Save();
}
private void purpleColor_Click(object sender, RoutedEventArgs e)
{
var bc = new BrushConverter();
Main.Background = (Brush)bc.ConvertFrom("#FF8701B9");
startButton.Foreground = (Brush)bc.ConvertFrom("#FF8701B9");
closeButton.Foreground = (Brush)bc.ConvertFrom("#FF8701B9");
}
I think I need the last clicked Button to be saved because I have allot of colors and maybe the .RaiseEvent can help here.
This is how it looks like:
Those 3 little buttons:
white
blue
red
are for changing the look of the program. At every start, the default is back.
You can store the color as a simple string and TypeConverter automatically converts it to type Brush. Below is an example.
Binding default value from XAML:
xmlns:properties="clr-namespace:WorkWithSettings.Properties"
<Button Width="100" Height="30"
Background="{Binding Source={x:Static properties:Settings.Default}, Path=Setting, Mode=TwoWay}" />
Set value from code:
private void Button_Click(object sender, RoutedEventArgs e)
{
WorkWithSettings.Properties.Settings.Default.Setting = "#FF007CE4";
}
Note: Setting - this is just the type of String.
More information you can see here:
TypeConverters and XAML
Edit:
Below I'll show you an example, that I hope will help you.
So, go into the settings of the project: Project -> Properties -> Parameters. This opens a window of approximately:
Here we have a property ButtonColor, defined in the settings. For example, I took the Button, which changes the background, depending on the color of the pressed button.
In order to property Background the synchronize with settings to do, so:
<Button Width="100" Height="30"
Content="TestButton"
Background="{Binding Source={x:Static properties:Settings.Default}, Path=ButtonColor, Mode=TwoWay}" />
The default background color of white. Now, to set the background color at the button, we change the parameter settings, like this:
private void Blue_Click(object sender, RoutedEventArgs e)
{
WorkWithSettings.Properties.Settings.Default.ButtonColor = "Blue";
}
To save changes to the settings, you need to call a method Save():
private void Save_Click(object sender, RoutedEventArgs e)
{
WorkWithSettings.Properties.Settings.Default.Save();
}
Now, the next time you start the program, the color will be the one that was set last.
Full example
XAML
<Window x:Class="WorkWithSettings.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:properties="clr-namespace:WorkWithSettings.Properties"
WindowStartupLocation="CenterScreen"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TextBlock Width="100" Height="30" Text="{Binding Source={x:Static properties:Settings.Default}, Path=ButtonColor, Mode=TwoWay}" Margin="0,60,0,0" />
<Button Width="100" Height="30" Content="TestButton" Background="{Binding Source={x:Static properties:Settings.Default}, Path=ButtonColor, Mode=TwoWay}" />
<WrapPanel>
<Button Name="Blue" Width="100" Height="30" Content="BlueColor" VerticalAlignment="Top" Click="Blue_Click" />
<Button Name="Red" Width="100" Height="30" Content="RedColor" VerticalAlignment="Top" Click="Red_Click" />
<Button Name="White" Width="100" Height="30" Content="WhiteColor" VerticalAlignment="Top" Click="White_Click" />
</WrapPanel>
<Button Name="Save" Width="60" Height="30" Content="Save" VerticalAlignment="Top" HorizontalAlignment="Right" Click="Save_Click" />
</Grid>
</Window>
Code behind
namespace WorkWithSettings
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void White_Click(object sender, RoutedEventArgs e)
{
WorkWithSettings.Properties.Settings.Default.ButtonColor = "White";
}
private void Blue_Click(object sender, RoutedEventArgs e)
{
WorkWithSettings.Properties.Settings.Default.ButtonColor = "Blue";
}
private void Red_Click(object sender, RoutedEventArgs e)
{
WorkWithSettings.Properties.Settings.Default.ButtonColor = "Red";
}
private void Save_Click(object sender, RoutedEventArgs e)
{
WorkWithSettings.Properties.Settings.Default.Save();
}
}
}
Output
You probably need to create items in the Settings tab of your project that store the information about the color. I would recommend storing the hex strings. Then, on MainForm_Load retrieve those values.
Make sure to also put the settings in the User scope, or else they will reset each time they close the application.
Since the xaml window stopped showing my wpf form using VS 2012 (after I added some comments to the top of the main .cs form), I reverted back to C# Express 2010.
I copied my xaml and code and pasted them into the new project.
However, I'm getting err msgs such as:
*'duckbilledPlatypusInfoMailer_Express.MainWindow' does not contain a definition for 'MainWindow_Loaded' and no extension method 'MainWindow_Loaded' accepting a first argument of type 'duckbilledPlatypusInfoMailer_Express.MainWindow' could be found (are you missing a using directive or an assembly reference?)*
and:
The name 'InitializeComponent' does not exist in the current context
I get the same err msg about two controls, my label and button (but not the DatePicker!)
So both of my event handlers, and two of my three controls, as well as the 'InitializeComponent' have been rendered in a cloak of invisibility, as far as VC#2010 is concerned...???
Here is my xaml and code (minimal, so p[a,o]sting all of it):
XAML:
<Window x:Class="duckbilledPlatypusInfoMailer_Express.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Duckbilled Platypus Info Mailer" SizeToContent="WidthAndHeight" WindowStartupLocation="CenterScreen" MinHeight="350" MinWidth="525" Loaded="MainWindow_Loaded" >
<StackPanel>
<StackPanel Orientation="Horizontal">
<Button x:Name="btnSelectPDFFile" HorizontalAlignment="Left" Padding="4" Margin="4" Width="120" Click="btnSelectPDFFile_Click" IsDefault="True">Select PDF File
</Button>
<Label x:Name="lblPlatypusSheetFile" Margin="4" >[Selected File]</Label>
</StackPanel>
<StackPanel Orientation="Horizontal">
<DatePicker ></DatePicker>
</StackPanel>
</StackPanel>
</Window>
CODE:
using System;
using System.Windows;
using duckbilledPlatypusInfoMailer;
namespace PlatypusInfo_Express
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
btnSelectPDFFile.Focus();
}
private void btnSelectPDFFile_Click(object sender, RoutedEventArgs e)
{
var dlg = new Microsoft.Win32.OpenFileDialog
{
InitialDirectory = #"C:\Scrooge\McDuckbilledPlatypus\",
DefaultExt = ".pdf",
Filter = "Platypus Data Sheets (sa*.pdf)|sa*.pdf"
};
bool? result = dlg.ShowDialog();
if (result == true)
{
string pdfFilename = dlg.FileName;
// Show just the file name, without the path
string pdfFileNameOnly = System.IO.Path.GetFileName(pdfFilename);
lblReviewSheetFile.Content = pdfFileNameOnly;
string textFilename = String.Format(#"C:\Scrooge\McDuckbilledPlatypus\{0}.txt", pdfFileNameOnly);
var pdfParser = new PDFParser();
if (pdfParser.ExtractText(pdfFilename, textFilename))
{
System.Diagnostics.Process.Start(textFilename);
}
else
{
MessageBox.Show("There was a boo-boo, Yogi!");
}
}
}
}
}
BTW, I did add the necessary 3rd party file to my solution (PDFParser.cs) as well as the two necessary references.
Note: If I right-click the event handlers in the xaml, it DOES take me to those event handlers in the cs file. So it knows where they are, why does it say they don't exist or it can't find them?
UPDATE
Here's the first part of the error I see in the WPF designer:
System.NotSupportedException
An attempt was made to load an assembly from a network location which would have caused the assembly to be sandboxed in previous versions of the .NET Framework. This release of the .NET Framework does not enable CAS policy by default, so this load may be dangerous. If this load is not intended to sandbox the assembly, please enable the loadFromRemoteSources switch. See http://go.microsoft.com/fwlink/?LinkId=155569 for more information.
at Microsoft.Expression.DesignHost.Isolation.Remoting.STAMarshaler.WaitForCompletion(NestedCallContext nestedCallContext, BlockingCall call, WaitHandle timeoutSignal)
at Microsoft.Expression.DesignHost.Isolation.Remoting.STAMarshaler.MarshalOut(Action action, Int32 targetApartmentId, WaitHandle aborted, WaitHandle timeoutSignal)
at Microsoft.Expression.DesignHost.Isolation.Remoting.ThreadMarshaler.MarshalOut[TValue](RemoteHandle1 targetObject, Action action)
at Microsoft.Expression.DesignHost.Isolation.Remoting.ThreadMarshaler.MarshalOut[TResult,TValue](RemoteHandle1 targetObject, Func`2 func)
There is an extra duckbilled in the namespace in the XAML :
<Window x:Class="duckbilledPlatypusInfoMailer_Express.MainWindow"
it has to be in the same namespace as to code behind class.