Search code examples
c#bindingdesktopwinui-3contentdialog

C# WinUI 3 Bind ContentDialog


I have a ContentDialog triggered when a user clicks on a row in a DataGrid. The primary goal of the ContentDialog is to allow the user to enter and save a comment via a textbox control named 'Cmnt_Apprvl_Mgmt' in the ContentDialog. The logic is working now.

Now I would like some of the data from the clicked row from the DataGrid to appear in the ContentDialog. I have not been able to figure out how to do it.

I pass 'rowModel' (data from the datagrid) as a parameter to the new contentdialog (v3). I would like any previous comment already entered for a particular row to populate the textbox 'Cmnt_Apprvl_Mgmt' in the ContentDialog.

Thank you in advance StackOverflow-contributors, you have been so helpful to me during this project. It is greatly appreciated.

My code: (xaml)

<ContentDialog x:Name="MgmtApprovalDialog"
               Title = "Enter Management Approval Comment"
               PrimaryButtonText="Save"
               CloseButtonText="Cancel"
               Opened="MgmtApprovalDialog_Opened"
               PrimaryButtonClick="MgmtApprovalDialog_PrimaryButtonClick">
    <StackPanel>
        <TextBox x:Name="Cmnt_Apprvl_Mgmt" PlaceholderText="Enter Comment" Margin="0 0 0 0" TextWrapping="Wrap" Height="80" TextChanged="Cmnt_Apprvl_Mgmt_TextChanged"/>
        <TextBlock x:Name="errorTextBlock" Margin="0 10 0 5" FontWeight="Bold" FontStyle="Oblique"/>
        <!-- Content body -->
        <TextBlock Name="body" TextWrapping="Wrap">
            <TextBlock.Text>
                When a target is not met, a comment from management is required (long and detailed)                       
            </TextBlock.Text>
        </TextBlock>
    </StackPanel>
</ContentDialog>

C#

private void MgmtApprovalDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
{
            // Ensure the comment field is empty. If a required field
            // is empty, set args.Cancel = true to keep the dialog open.
            if (string.IsNullOrEmpty(Cmnt_Apprvl_Mgmt.Text))
            {
                args.Cancel = true;
                errorTextBlock.Text = "Comment is required.";
            }
}
            
private void DataGrid_Detail_PointerReleased(object sender, PointerRoutedEventArgs e)
            {
                DataGridRow clickedRow = FindParent<DataGridRow>((UIElement)e.OriginalSource);
                if (clickedRow != null)
                {
                    Approvals rowModel = (Approvals)clickedRow.DataContext;
                    // Do stuff
                    // DisplayCommentDialog();
                    //DisplayCommentDialog_v2(rowModel);
                    DisplayCommentDialog_v3(rowModel);
                }
            }

        // +---------------------------------------------------------
        // | DISPLAY COMMENT DIALOG V3
        // +---------------------------------------------------------
        private async void DisplayCommentDialog_v3(Approvals rowModel)
        {
            ContentDialogResult result = await MgmtApprovalDialog.ShowAsync();
            if (result == ContentDialogResult.Primary)
            {
                // Save button clicked
                Debug.WriteLine($"+-------------------------------------------------------------------");
                Debug.WriteLine($"| Hello - inside DisplayCommentDialog_v3 Primary Button Clicked!");
                Debug.WriteLine($"| Hello - Comment ID  : {rowModel.Comment_ID}");
                Debug.WriteLine($"| Hello - Comment Text: {Cmnt_Apprvl_Mgmt.Text}");
                Debug.WriteLine($"+-------------------------------------------------------------------");
                SaveMgMtApprovalComment(rowModel.Comment_ID, Cmnt_Apprvl_Mgmt.Text);
                // Before refreshing the DataGrid_Detail you must re-pull from the server (this may be a design flaw.)
                GetSQLData_Approvals();
                // Refresh DataGrid_Detail so the user can see what was just entered
                PopulateApprovalDetDG(v_product);
            }
            else
            {
                // User pressed Cancel, ESC, or the back arrow.
                // Terms of use were not accepted.
                Debug.WriteLine($"+-------------------------------------------------------------------");
                Debug.WriteLine($"| Hello - inside DisplayCommentDialog_v3 (Cancel, ESC, or back arrow)");
                Debug.WriteLine($"+-------------------------------------------------------------------");
            }
        }

Solution

  • Solution 1: DataContext and Bindings

    An easy solution is the one proposed by Simon Mourier in his comment.

    Simply set the DataContext of your ContentDialog to the selected item to enable binding on its properties.

    private async void DisplayCommentDialog_v3(Approvals rowModel)
    {
        MgmtApprovalDialog.DataContext = rowModel;
        ContentDialogResult result = await MgmtApprovalDialog.ShowAsync();
    

    Then, assuming Approvals has a string Comment property, you can use the following binding on your TextBox.

    <TextBox Text="{Binding Comment}" (...) />
    

    Solution 2: Subclass ContentDialog

    If you don't want to use bindings, you can also create a class derived from ContentDialog which allows you to add custom logic and expose extra members. You can find an example of this here.

    In your case it could look like the following.

    public sealed partial class ApprovalDialog: ContentDialog
    {
        public ApprovalDialog()
        {
            this.InitializeComponent();        
        }
    
        public void SetComment(string comment)
        {
            Cmnt_Apprvl_Mgmt.Text = comment;
        }
    }
    

    Then you would call the extra method before showing the dialog:

    private async void DisplayCommentDialog_v3(Approvals rowModel)
    {
        // Again, I don't know if `Comment` is the correct property name.
        MgmtApprovalDialog.SetComment(rowModel.Comment);
        ContentDialogResult result = await MgmtApprovalDialog.ShowAsync();
    

    You would also need to change your xaml to include x:Class to specify your custom type.

    <ContentDialog x:Class="YourNameSpace.ApprovalDialog"
                   x:Name="MgmtApprovalDialog"
                   Title = "Enter Management Approval Comment"
          (...)