✅ How to get data out of a custom control?

Currently, I'm doing a custom user control for a password box with a label showcasing what to put in there. Right now, this is the content of my user control:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{Binding LabelText, ElementName=root}" Height="24" Margin="0 0 0 5" Grid.Column="0"/>
<PasswordBox Width="200" Height="24" Password="{Binding Password, ElementName=root}" Grid.Column="1"/>
</Grid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{Binding LabelText, ElementName=root}" Height="24" Margin="0 0 0 5" Grid.Column="0"/>
<PasswordBox Width="200" Height="24" Password="{Binding Password, ElementName=root}" Grid.Column="1"/>
</Grid>
And this is the .cs file:
using System.Windows;
using System.Windows.Controls;

namespace WoWSpect.Components;

public partial class PasswordBoxWithLabel : UserControl
{
public static readonly DependencyProperty LabelTextProperty = DependencyProperty.Register(
nameof(LabelTextProperty), typeof(string), typeof(PasswordBoxWithLabel), new PropertyMetadata(string.Empty));

public static readonly DependencyProperty PasswordProperty = DependencyProperty.Register(
nameof(Password), typeof(string), typeof(PasswordBoxWithLabel), new PropertyMetadata(string.Empty));

public string Password
{
get { return (string)GetValue(PasswordProperty); }
set { SetValue(PasswordProperty, value); }
}

public string LabelText
{
get { return (string)GetValue(LabelTextProperty); }
set { SetValue(LabelTextProperty, value); }
}

public PasswordBoxWithLabel()
{
InitializeComponent();
}
}
using System.Windows;
using System.Windows.Controls;

namespace WoWSpect.Components;

public partial class PasswordBoxWithLabel : UserControl
{
public static readonly DependencyProperty LabelTextProperty = DependencyProperty.Register(
nameof(LabelTextProperty), typeof(string), typeof(PasswordBoxWithLabel), new PropertyMetadata(string.Empty));

public static readonly DependencyProperty PasswordProperty = DependencyProperty.Register(
nameof(Password), typeof(string), typeof(PasswordBoxWithLabel), new PropertyMetadata(string.Empty));

public string Password
{
get { return (string)GetValue(PasswordProperty); }
set { SetValue(PasswordProperty, value); }
}

public string LabelText
{
get { return (string)GetValue(LabelTextProperty); }
set { SetValue(LabelTextProperty, value); }
}

public PasswordBoxWithLabel()
{
InitializeComponent();
}
}
But as soon as I use it somewhere to display something, I get this error: System.Windows.Markup.XamlParseException: A 'Binding' cannot be set on the 'Password' property of type 'PasswordBox'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject. How can I fix it? I need to get the password out of the password box from my user control, but since I cannot use a property apparently, I don't know another way to do it.
56 Replies
Kouhai
Kouhai5mo ago
The Password property in PasswordBox is not a DependencyProperty, so you can't use Binding Your best solution would be setting up a handler for the PasswordChanged event
Ellen Joe.♡
Ellen Joe.♡OP5mo ago
Do you mean something like this?
public partial class PasswordBoxWithLabel : UserControl
{
public static readonly DependencyProperty LabelTextProperty = DependencyProperty.Register(
nameof(LabelText), typeof(string), typeof(PasswordBoxWithLabel), new PropertyMetadata(string.Empty));

public static readonly DependencyProperty PasswordProperty = DependencyProperty.Register(
nameof(Password), typeof(string), typeof(PasswordBoxWithLabel), new PropertyMetadata(string.Empty));

public static readonly DependencyProperty LabelColorProperty = DependencyProperty.Register(
nameof(LabelColor), typeof(Brush), typeof(PasswordBoxWithLabel), new PropertyMetadata(Brushes.White));

public Brush LabelColor
{
get { return (Brush)GetValue(LabelColorProperty); }
set { SetValue(LabelColorProperty, value); }
}

public string Password
{
get { return (string)GetValue(PasswordProperty); }
set { SetValue(PasswordProperty, value); }
}

public string LabelText
{
get { return (string)GetValue(LabelTextProperty); }
set { SetValue(LabelTextProperty, value); }
}

public PasswordBoxWithLabel()
{
InitializeComponent();
}

private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
{
Password = inputBox.Password;
}
}
public partial class PasswordBoxWithLabel : UserControl
{
public static readonly DependencyProperty LabelTextProperty = DependencyProperty.Register(
nameof(LabelText), typeof(string), typeof(PasswordBoxWithLabel), new PropertyMetadata(string.Empty));

public static readonly DependencyProperty PasswordProperty = DependencyProperty.Register(
nameof(Password), typeof(string), typeof(PasswordBoxWithLabel), new PropertyMetadata(string.Empty));

public static readonly DependencyProperty LabelColorProperty = DependencyProperty.Register(
nameof(LabelColor), typeof(Brush), typeof(PasswordBoxWithLabel), new PropertyMetadata(Brushes.White));

public Brush LabelColor
{
get { return (Brush)GetValue(LabelColorProperty); }
set { SetValue(LabelColorProperty, value); }
}

public string Password
{
get { return (string)GetValue(PasswordProperty); }
set { SetValue(PasswordProperty, value); }
}

public string LabelText
{
get { return (string)GetValue(LabelTextProperty); }
set { SetValue(LabelTextProperty, value); }
}

public PasswordBoxWithLabel()
{
InitializeComponent();
}

private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
{
Password = inputBox.Password;
}
}
XML:
<PasswordBox x:Name="inputBox"
Width="200"
Height="24"
PasswordChanged="PasswordBox_PasswordChanged"
Grid.Column="1"
Style="{StaticResource StylizedPasswordBox}"/>
<PasswordBox x:Name="inputBox"
Width="200"
Height="24"
PasswordChanged="PasswordBox_PasswordChanged"
Grid.Column="1"
Style="{StaticResource StylizedPasswordBox}"/>
Kouhai
Kouhai5mo ago
Yeah, that should work
Ellen Joe.♡
Ellen Joe.♡OP5mo ago
It does not :'D And I'm struggling to understand why I use them like this:
<components:PasswordBoxWithLabel LabelText="Client ID"
LabelColor="{StaticResource TextColorBrush}"
Password="{Binding ClientId}"
Margin="0 10 0 0"/>
<components:PasswordBoxWithLabel LabelText="Client Secret"
LabelColor="{StaticResource TextColorBrush}"
Password="{Binding ClientSecret}"
Margin="0 10 0 0"/>
<components:PasswordBoxWithLabel LabelText="Client ID"
LabelColor="{StaticResource TextColorBrush}"
Password="{Binding ClientId}"
Margin="0 10 0 0"/>
<components:PasswordBoxWithLabel LabelText="Client Secret"
LabelColor="{StaticResource TextColorBrush}"
Password="{Binding ClientSecret}"
Margin="0 10 0 0"/>
In my VM it's setup like this (I use CommunityToolkit.Mvvm):
private string _clientID;
private string _clientSecret;

public string ClientId
{
get => _clientID;
set => SetProperty(ref _clientID, value);
}

public string ClientSecret
{
get => _clientSecret;
set => SetProperty(ref _clientSecret, value);
}
private string _clientID;
private string _clientSecret;

public string ClientId
{
get => _clientID;
set => SetProperty(ref _clientID, value);
}

public string ClientSecret
{
get => _clientSecret;
set => SetProperty(ref _clientSecret, value);
}
Kouhai
Kouhai5mo ago
Hmmm, the event PasswordBox_PasswordChanged gets called right? Also if you're using CommunityToolkit.Mvvm you can shorten your code a bit like this ```cs [ObservableProperty] private string _clientSecret; [ObservableProperty] private string _clientID; ``` These attributes on the fields will automatically generate properties You'll need to set the class to partial` as well
Ellen Joe.♡
Ellen Joe.♡OP5mo ago
Yes, the event gets called And ty for the tip with the ObservableProperty attribute, i forgot it existed
Ellen Joe.♡
Ellen Joe.♡OP5mo ago
it also changed the property correctly when i typed in "a"
No description
Kouhai
Kouhai5mo ago
Hmmmm Have you tried setting the mode to "TwoWay"?
<components:PasswordBoxWithLabel LabelText="Client Secret"
LabelColor="{StaticResource TextColorBrush}"
Password="{Binding ClientSecret, Mode=TwoWay}"
Margin="0 10 0 0"/>
<components:PasswordBoxWithLabel LabelText="Client Secret"
LabelColor="{StaticResource TextColorBrush}"
Password="{Binding ClientSecret, Mode=TwoWay}"
Margin="0 10 0 0"/>
@Furina.♡ OneWayToSource should also work
Ellen Joe.♡
Ellen Joe.♡OP5mo ago
Now it works!! Ty a lot It was the mode i needed to provide
Kouhai
Kouhai5mo ago
:HYPERS:
Ellen Joe.♡
Ellen Joe.♡OP5mo ago
Ok I was happy too early. When I type in the box now and press on my save button, it saves it to my settings file. But when I change the view to sth else and then back to my Settings View, the boxes are empty again. When I change to the view, the view model gets the data from the settings file tho. Any idea on how to fix that?
leowest
leowest5mo ago
if you're using CTK why do u have all the boilerplate in there still? also how are u setting the datacontext of the settings? are u using DI or its manually done
Ellen Joe.♡
Ellen Joe.♡OP5mo ago
I set it in the view via
<UserControl.DataContext>
<viewModels:SettingsVM />
</UserControl.DataContext>
<UserControl.DataContext>
<viewModels:SettingsVM />
</UserControl.DataContext>
leowest
leowest5mo ago
that doesn't set the context
Ellen Joe.♡
Ellen Joe.♡OP5mo ago
It doesn't?
leowest
leowest5mo ago
nope alas its empty
Ellen Joe.♡
Ellen Joe.♡OP5mo ago
Do i need to do it like this then?
public partial class SettingsView : UserControl
{
public SettingsView()
{
InitializeComponent();
DataContext = new SettingsVM();
}
}
public partial class SettingsView : UserControl
{
public SettingsView()
{
InitializeComponent();
DataContext = new SettingsVM();
}
}
leowest
leowest5mo ago
well it depends are u using Dependency injection? if not then yes u would manually set it either there or when u create the window and that means if u dispose of that window u would required logic to load the settings when its created i.e.: wiring the Load method of the View into the VM so it can load the settings when its created
Ellen Joe.♡
Ellen Joe.♡OP5mo ago
How exactly do i do that? It's my first time using MVVM + WPF And I'm not using dependency injection
leowest
leowest5mo ago
ok then u create the Load event in your view for example:
public partial class SettingsView : Window
{
public SettingsViewModel ViewModel => (SettingsViewModel)DataContext!;

public SettingsView()
{
InitializeComponent();
DataContext = new SettingsVM();
Loaded += SettingsView_Loaded;
}

private void SettingsView_Loaded(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
{
ViewModel.OnLoaded();
}
}
public partial class SettingsView : Window
{
public SettingsViewModel ViewModel => (SettingsViewModel)DataContext!;

public SettingsView()
{
InitializeComponent();
DataContext = new SettingsVM();
Loaded += SettingsView_Loaded;
}

private void SettingsView_Loaded(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
{
ViewModel.OnLoaded();
}
}
And have a method in your ViewModel called OnLoaded for example. so what this would do is, when the view is loaded, it would call the Loaded event, which in turn would call the VM method which would do the loading of your settings either deserializing from a file and populating the properties in your VM or something I dont know how you're saving the settings
Ellen Joe.♡
Ellen Joe.♡OP5mo ago
I have a static class dealing with the handling of the settings stuff in the file So I basically do this in my view model now:
public void LoadSettings()
{
string[] keys = [AppConfigHandler.ClientIdKey, AppConfigHandler.ClientSecretKey];

if (AppConfigHandler.TryGetValues(keys, out IDictionary<string, string> values))
{
ClientID = values.TryGetValue(AppConfigHandler.ClientIdKey, out string clientId) ? clientId : string.Empty;
ClientSecret = values.TryGetValue(AppConfigHandler.ClientSecretKey, out string clientSecret) ? clientSecret : string.Empty;
}
else
{
ClientID = string.Empty;
ClientSecret = string.Empty;
}
}
public void LoadSettings()
{
string[] keys = [AppConfigHandler.ClientIdKey, AppConfigHandler.ClientSecretKey];

if (AppConfigHandler.TryGetValues(keys, out IDictionary<string, string> values))
{
ClientID = values.TryGetValue(AppConfigHandler.ClientIdKey, out string clientId) ? clientId : string.Empty;
ClientSecret = values.TryGetValue(AppConfigHandler.ClientSecretKey, out string clientSecret) ? clientSecret : string.Empty;
}
else
{
ClientID = string.Empty;
ClientSecret = string.Empty;
}
}
I get the current ClientID and the ClientSecret from my file. This already works. My view is a UserControl. I've done it like this now:
public partial class SettingsView : UserControl
{
private SettingsVM ViewModel => (SettingsVM)DataContext;

public SettingsView()
{
InitializeComponent();
DataContext = new SettingsVM();
Loaded += (s, e) => ViewModel.LoadSettings();
}
}
public partial class SettingsView : UserControl
{
private SettingsVM ViewModel => (SettingsVM)DataContext;

public SettingsView()
{
InitializeComponent();
DataContext = new SettingsVM();
Loaded += (s, e) => ViewModel.LoadSettings();
}
}
And it still doesn't work :'D
leowest
leowest5mo ago
sure
Ellen Joe.♡
Ellen Joe.♡OP5mo ago
When I'm debugging the LoadSettings method with a breakpoint, it gets into the if statement instead of the else statement With the corresponding data for ClientID and ClientSecret
leowest
leowest5mo ago
ok so Loadsettings is working?
Ellen Joe.♡
Ellen Joe.♡OP5mo ago
Yes, that method is working
leowest
leowest5mo ago
inside the vm correct?
Ellen Joe.♡
Ellen Joe.♡OP5mo ago
Yes But the view does not get the updated properties
leowest
leowest5mo ago
can you post your VM?
Ellen Joe.♡
Ellen Joe.♡OP5mo ago
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using WoWSpect.ConfigHandler;

public partial class SettingsVM : ObservableObject
{
[ObservableProperty]
private string _clientID;

[ObservableProperty]
private string _clientSecret;


public SettingsVM()
{
LoadSettings();
}

public void LoadSettings()
{
string[] keys = [AppConfigHandler.ClientIdKey, AppConfigHandler.ClientSecretKey];

if (AppConfigHandler.TryGetValues(keys, out IDictionary<string, string> values))
{
ClientID = values.TryGetValue(AppConfigHandler.ClientIdKey, out string clientId) ? clientId : string.Empty;
ClientSecret = values.TryGetValue(AppConfigHandler.ClientSecretKey, out string clientSecret) ? clientSecret : string.Empty;
}
else
{
ClientID = string.Empty;
ClientSecret = string.Empty;
}
}

[RelayCommand]
private void SaveSettings()
{
Dictionary<string, string> values = new Dictionary<string, string>
{
[AppConfigHandler.ClientIdKey] = ClientID,
[AppConfigHandler.ClientSecretKey] = ClientSecret
};

AppConfigHandler.SetValues(values);
}
}
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using WoWSpect.ConfigHandler;

public partial class SettingsVM : ObservableObject
{
[ObservableProperty]
private string _clientID;

[ObservableProperty]
private string _clientSecret;


public SettingsVM()
{
LoadSettings();
}

public void LoadSettings()
{
string[] keys = [AppConfigHandler.ClientIdKey, AppConfigHandler.ClientSecretKey];

if (AppConfigHandler.TryGetValues(keys, out IDictionary<string, string> values))
{
ClientID = values.TryGetValue(AppConfigHandler.ClientIdKey, out string clientId) ? clientId : string.Empty;
ClientSecret = values.TryGetValue(AppConfigHandler.ClientSecretKey, out string clientSecret) ? clientSecret : string.Empty;
}
else
{
ClientID = string.Empty;
ClientSecret = string.Empty;
}
}

[RelayCommand]
private void SaveSettings()
{
Dictionary<string, string> values = new Dictionary<string, string>
{
[AppConfigHandler.ClientIdKey] = ClientID,
[AppConfigHandler.ClientSecretKey] = ClientSecret
};

AppConfigHandler.SetValues(values);
}
}
leowest
leowest5mo ago
remove the LoadSettings from the constructor and check if its being called still
Ellen Joe.♡
Ellen Joe.♡OP5mo ago
It's removed and it's still being called
leowest
leowest5mo ago
k is your project on github? Apparent I dont see anything off right now
Ellen Joe.♡
Ellen Joe.♡OP5mo ago
It is, but it's a private repository currently
leowest
leowest5mo ago
well can u make it public or something so I can clone and see whats up
Ellen Joe.♡
Ellen Joe.♡OP5mo ago
I unfortunately cannot because it's for an academic assignment and it will look very weird when other people are also in there :'D
leowest
leowest5mo ago
understood, well I can only think your usercontrol is at fault then something missing or done wrong because on vm/view side things look ok at first glance and as u said your self things are connecting properly except with your control
Ellen Joe.♡
Ellen Joe.♡OP5mo ago
I can post my usercontrol xml here if it might help
<UserControl x:Class="WoWSpect.MVVM.Views.SettingsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WoWSpect.MVVM.Views"
xmlns:viewModels="clr-namespace:WoWSpect.MVVM.ViewModels"
xmlns:components="clr-namespace:WoWSpect.Components"
mc:Ignorable="d"
d:DesignHeight="570" d:DesignWidth="675"
d:Background="DimGray">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/ResourceDictionaries/Buttons.xaml"/>
<ResourceDictionary Source="/ResourceDictionaries/Texts.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<UserControl.DataContext>
<viewModels:SettingsVM />
</UserControl.DataContext>

<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="Auto"/>
<RowDefinition Height="*" />
</Grid.RowDefinitions>

<TextBlock Grid.Row="0"
Margin="20 5 0 0"
FontSize="18"
Foreground="White">Settings</TextBlock>
<Border Grid.Row="1" Height="1" Opacity="0.5" Margin="0 5 0 0 ">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="Transparent" Offset="0"/>
<GradientStop Color="#484b47" Offset="0.2"/>
<GradientStop Color="#484b47" Offset="0.6"/>
<GradientStop Color="Transparent" Offset="0.8"/>
</LinearGradientBrush>
</Border.Background>
</Border>
<ScrollViewer Grid.Row="2" VerticalScrollBarVisibility="Auto">
<StackPanel Margin="40 5 0 0">
<components:PasswordBoxWithLabel LabelText="Client ID"
LabelColor="{StaticResource TextColorBrush}"
Password="{Binding ClientID, Mode=TwoWay }"
Margin="0 10 0 0"/>
<components:PasswordBoxWithLabel LabelText="Client Secret"
LabelColor="{StaticResource TextColorBrush}"
Password="{Binding ClientSecret, Mode=TwoWay }"
Margin="0 10 0 0"/>
<Grid Margin="0 50 0 0">
<Button Style="{StaticResource InteractionButton}"
Width="100"
Height="30"
Margin="200 30 0 0"
Command="{Binding SaveSettingsCommand}">
Save
</Button>
</Grid>
</StackPanel>
</ScrollViewer>
</Grid>
</UserControl>
<UserControl x:Class="WoWSpect.MVVM.Views.SettingsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WoWSpect.MVVM.Views"
xmlns:viewModels="clr-namespace:WoWSpect.MVVM.ViewModels"
xmlns:components="clr-namespace:WoWSpect.Components"
mc:Ignorable="d"
d:DesignHeight="570" d:DesignWidth="675"
d:Background="DimGray">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/ResourceDictionaries/Buttons.xaml"/>
<ResourceDictionary Source="/ResourceDictionaries/Texts.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<UserControl.DataContext>
<viewModels:SettingsVM />
</UserControl.DataContext>

<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="Auto"/>
<RowDefinition Height="*" />
</Grid.RowDefinitions>

<TextBlock Grid.Row="0"
Margin="20 5 0 0"
FontSize="18"
Foreground="White">Settings</TextBlock>
<Border Grid.Row="1" Height="1" Opacity="0.5" Margin="0 5 0 0 ">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="Transparent" Offset="0"/>
<GradientStop Color="#484b47" Offset="0.2"/>
<GradientStop Color="#484b47" Offset="0.6"/>
<GradientStop Color="Transparent" Offset="0.8"/>
</LinearGradientBrush>
</Border.Background>
</Border>
<ScrollViewer Grid.Row="2" VerticalScrollBarVisibility="Auto">
<StackPanel Margin="40 5 0 0">
<components:PasswordBoxWithLabel LabelText="Client ID"
LabelColor="{StaticResource TextColorBrush}"
Password="{Binding ClientID, Mode=TwoWay }"
Margin="0 10 0 0"/>
<components:PasswordBoxWithLabel LabelText="Client Secret"
LabelColor="{StaticResource TextColorBrush}"
Password="{Binding ClientSecret, Mode=TwoWay }"
Margin="0 10 0 0"/>
<Grid Margin="0 50 0 0">
<Button Style="{StaticResource InteractionButton}"
Width="100"
Height="30"
Margin="200 30 0 0"
Command="{Binding SaveSettingsCommand}">
Save
</Button>
</Grid>
</StackPanel>
</ScrollViewer>
</Grid>
</UserControl>
leowest
leowest5mo ago
would also need to see these 2 <ResourceDictionary Source="/ResourceDictionaries/Buttons.xaml"/> <ResourceDictionary Source="/ResourceDictionaries/Texts.xaml"/> and PasswordBoxWithLabel can u do $paste instead
MODiX
MODiX5mo ago
If your code is too long, you can post to https://paste.mod.gg/, save, and copy the link into chat for others to see your shared code!
leowest
leowest5mo ago
because the file embed from discord is awful
Ellen Joe.♡
Ellen Joe.♡OP5mo ago
Sure
leowest
leowest5mo ago
and it will be more organized with all files in one paste
Ellen Joe.♡
Ellen Joe.♡OP5mo ago
BlazeBin - bxrwowsorycb
A tool for sharing your source code with the world!
Ellen Joe.♡
Ellen Joe.♡OP5mo ago
I dont know how to rename the first file, but the first one (newfile) is the Buttons.xaml
Ellen Joe.♡
Ellen Joe.♡OP5mo ago
And here is the MainWindowVM https://paste.mod.gg/gsaczheztbgq/0
BlazeBin - gsaczheztbgq
A tool for sharing your source code with the world!
leowest
leowest5mo ago
missing TextColorBrush
Ellen Joe.♡
Ellen Joe.♡OP5mo ago
<Color x:Key="TextColor">#f8cb00</Color>
<SolidColorBrush x:Key="TextColorBrush" Color="{StaticResource TextColor}"/>
<Color x:Key="TextColor">#f8cb00</Color>
<SolidColorBrush x:Key="TextColorBrush" Color="{StaticResource TextColor}"/>
(In the Application resources)
leowest
leowest5mo ago
StylizedPasswordBox ah nvm its there
Ellen Joe.♡
Ellen Joe.♡OP5mo ago
Should be in this link in TextBoxes.xaml
leowest
leowest5mo ago
yeah I just hadn't open it yet I will have to leave my sit for a few but I will get back to u in a few
Ellen Joe.♡
Ellen Joe.♡OP5mo ago
Alright, I'ma take a break from coding in the meantime
leowest
leowest5mo ago
so yeah I just recall you cant bind to it because its a SecureString and u can't just dp into it with a string so the "Password" is conflicting what I would suggest is keep the clientid display and hide just the secret and have the secret be a parameter in the command or use a helper https://stackoverflow.com/a/889005/450121 which will essentially make the secret available in memory and would pose a risk if u expect people to be trying to reverse eng it so you would remove the Password dp and property and have something like
public static readonly DependencyProperty ClearTextPasswordProperty = DependencyProperty.Register(
nameof(ClearTextPassword),
typeof(string),
typeof(PasswordBoxWithLabel),
new FrameworkPropertyMetadata(default(string), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

public string? ClearTextPassword
{
get { return (string)GetValue(ClearTextPasswordProperty); }
set
{
SetValue(ClearTextPasswordProperty, value);
inputBox.Password = value;
}
}

private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
{
if (sender is not PasswordBox box) return;
SetCurrentValue(ClearTextPasswordProperty, box.Password);
}
public static readonly DependencyProperty ClearTextPasswordProperty = DependencyProperty.Register(
nameof(ClearTextPassword),
typeof(string),
typeof(PasswordBoxWithLabel),
new FrameworkPropertyMetadata(default(string), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

public string? ClearTextPassword
{
get { return (string)GetValue(ClearTextPasswordProperty); }
set
{
SetValue(ClearTextPasswordProperty, value);
inputBox.Password = value;
}
}

private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
{
if (sender is not PasswordBox box) return;
SetCurrentValue(ClearTextPasswordProperty, box.Password);
}
And in the settings.xaml in the passwordboxwithlabel
ClearTextPassword="{Binding ClientSecret}"
ClearTextPassword="{Binding ClientSecret}"
Ellen Joe.♡
Ellen Joe.♡OP5mo ago
I found a different fix with a helper class which is basically creating a copy of the password and attaching it to the password on load
public static class PasswordHelper
{
public static readonly DependencyProperty PasswordProperty = DependencyProperty.RegisterAttached("Password",
typeof(string), typeof(PasswordHelper), new FrameworkPropertyMetadata(string.Empty, OnPasswordPropertyChanged));

public static readonly DependencyProperty AttachProperty = DependencyProperty.RegisterAttached("Attach",
typeof(bool), typeof(PasswordHelper), new FrameworkPropertyMetadata(false, Attach));

public static readonly DependencyProperty IsUpdatingProperty = DependencyProperty.RegisterAttached("IsUpdating",
typeof(bool), typeof(PasswordHelper));

public static void SetAttach(DependencyObject dp, bool value)
{
dp.SetValue(AttachProperty, value);
}

public static bool GetAttach(DependencyObject dp)
{
return (bool) dp.GetValue(AttachProperty);
}

public static void SetPassword(DependencyObject dp, string value)
{
dp.SetValue(PasswordProperty, value);
}

public static string GetPassword(DependencyObject dp)
{
return (string)dp.GetValue(PasswordProperty);
}

public static void SetIsUpdating(DependencyObject dp, bool value)
{
dp.SetValue(IsUpdatingProperty, value);
}

public static bool GetIsUpdating(DependencyObject dp)
{
return (bool) dp.GetValue(IsUpdatingProperty);
}

private static void OnPasswordPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
if(sender is not PasswordBox passwordBox) return;

passwordBox.PasswordChanged -= PasswordBox_PasswordChanged;

if(!GetIsUpdating(passwordBox))
{
passwordBox.Password = (string) args.NewValue;
}

passwordBox.PasswordChanged += PasswordBox_PasswordChanged;
}

private static void Attach(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
if(sender is not PasswordBox passwordBox) return;

if((bool) args.OldValue)
{
passwordBox.PasswordChanged -= PasswordBox_PasswordChanged;
}

if((bool) args.NewValue)
{
passwordBox.PasswordChanged += PasswordBox_PasswordChanged;
}

}

private static void PasswordBox_PasswordChanged(object sender, RoutedEventArgs args)
{
if(sender is not PasswordBox passwordBox) return;

SetIsUpdating(passwordBox, true);

SetPassword(passwordBox, passwordBox.Password);

SetIsUpdating(passwordBox, false);
}
}
public static class PasswordHelper
{
public static readonly DependencyProperty PasswordProperty = DependencyProperty.RegisterAttached("Password",
typeof(string), typeof(PasswordHelper), new FrameworkPropertyMetadata(string.Empty, OnPasswordPropertyChanged));

public static readonly DependencyProperty AttachProperty = DependencyProperty.RegisterAttached("Attach",
typeof(bool), typeof(PasswordHelper), new FrameworkPropertyMetadata(false, Attach));

public static readonly DependencyProperty IsUpdatingProperty = DependencyProperty.RegisterAttached("IsUpdating",
typeof(bool), typeof(PasswordHelper));

public static void SetAttach(DependencyObject dp, bool value)
{
dp.SetValue(AttachProperty, value);
}

public static bool GetAttach(DependencyObject dp)
{
return (bool) dp.GetValue(AttachProperty);
}

public static void SetPassword(DependencyObject dp, string value)
{
dp.SetValue(PasswordProperty, value);
}

public static string GetPassword(DependencyObject dp)
{
return (string)dp.GetValue(PasswordProperty);
}

public static void SetIsUpdating(DependencyObject dp, bool value)
{
dp.SetValue(IsUpdatingProperty, value);
}

public static bool GetIsUpdating(DependencyObject dp)
{
return (bool) dp.GetValue(IsUpdatingProperty);
}

private static void OnPasswordPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
if(sender is not PasswordBox passwordBox) return;

passwordBox.PasswordChanged -= PasswordBox_PasswordChanged;

if(!GetIsUpdating(passwordBox))
{
passwordBox.Password = (string) args.NewValue;
}

passwordBox.PasswordChanged += PasswordBox_PasswordChanged;
}

private static void Attach(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
if(sender is not PasswordBox passwordBox) return;

if((bool) args.OldValue)
{
passwordBox.PasswordChanged -= PasswordBox_PasswordChanged;
}

if((bool) args.NewValue)
{
passwordBox.PasswordChanged += PasswordBox_PasswordChanged;
}

}

private static void PasswordBox_PasswordChanged(object sender, RoutedEventArgs args)
{
if(sender is not PasswordBox passwordBox) return;

SetIsUpdating(passwordBox, true);

SetPassword(passwordBox, passwordBox.Password);

SetIsUpdating(passwordBox, false);
}
}
leowest
leowest5mo ago
sure, more complex but works as well, just keep in mind that no matter what it will not be secure and the password will be in memory $close
MODiX
MODiX5mo ago
If you have no further questions, please use /close to mark the forum thread as answered
Ellen Joe.♡
Ellen Joe.♡OP5mo ago
Yea, but I use the password box just to hide it from the user in case they are streaming. That's the only reason I use it
Want results from more Discord servers?
Add your server